@cryptotaxi247 / netdata-1 / commits / c74bf56ee

Code reorg and cleanup - enrichment of /api/v2 (#15294)

* claim script now accepts the same params as the kickstart * rewrote buildinfo to unify all methods * added cloud unavailable in cloud status * added all exporters * renamed httpd to h2o * rename ENABLE_COMPRESSION to ENABLE_LZ4 * rename global variable * rename ENABLE_HTTPS to ENABLE_OPENSSL * fix coverity-scan for openssl * add lz4 to coverity-scan * added all plugins and most of the features * added all plugins and most of the features * generalize bitmap code so that we can have any size of bitmaps * cleanup * fix compilation without protobuf * fix compilation with others allocators * fix bitmap * comprehensive bitmaps unit test * bitmap as macros * added developer mode * added system info to build info * cloud available/unavailable * added /api/v2/info * added units and ni to transitions * when showing instances and transitions, show only the instances that have transitions * cleanup * add missing quotes * add anchor to transitions * added more to build info * calculate retention per tier and expose it to /api/v2/info * added currently collected metrics * do not show space and retention when no numbers are available * fix impossible overflow * Add function for transitions and execute callback * In case of error, reset and try next dictionary entry * Fix error message * simpler logic to maintain retention per tier * /api/v2/alert_transitions * Handle case of recipient null Convert after and before to usec * Add classification, type and component * working /api/v2/alert_transitions * Fix query to properly handle context and alert name * cleanup * Add search with transition * accept transition in /api/v2/alert_transitions * totaly dynamic facets * fixed debug info * restructured facets * cleanup; removal of options=transitions * updated alert entries flags * method to exec * Return also exec run timestamp Temp table cleanup only when we don't execute with a transition * cleanup obsolete anchor parameter * Add sql_get_alert_configuration function * added options=config to alert_transitions * added /api/v2/alert_config * preliminary work for /api/v2/claim * initialize variables; do not expose expected retention if no disk space info is available; do not report aclk as initializing when not claimed * fix claim session key filename * put a newline into the session key file * more progress on claiming * final /api/v2/claim endpoint * after claiming, refresh our state at the output * Fix query to fetch config * Remove debug log * add configuration objects * add configuration objects - fixed * respect the NETDATA_DISABLE_CLOUD env variable * NETDATA_DISABLE_CLOUD env variable sets the default, but the config sets the final value * use a new claimed_id on every claiming * regenerate random key on claiming and wait for online status * ignore write() return value when writing a newline * dont show cloud status disabled when claimed_id is missing * added ctx to alert instances * cleanup config and transitions from /api/v2/alerts * fix unused variable * in /api/v2/alert_config show 1 config without an array * show alert values conditionally, by appending options=values * When storing host info if the key value is empty, store unknown * added options=summary to control when the alerts summary is shown * increased http_api_v2 to version 5 * claming random key file is now not world readable * added local-listeners binary that detects all the listening ports, their IPs and their command lines --------- Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com>

Costa Tsaousis committed Jul 6, 2023 at 01:49 UTC c74bf56ee2910b5c90e5be2e31128580b85b9ca8
62 files changed +3965 -1327
.gitignore
+3
@@ -69,6 +69,9 @@ slabinfo.plugin
69 cgroup-network
70 !cgroup-network/
71
72 +local-listeners
73 +!local-listeners/
74 +
75 ebpf.plugin
76 collectors/ebpf.plugin/reset_netdata_trace.sh
77 !ebpf.plugin/
.gitmodules
+2 -2
@@ -9,7 +9,7 @@
9 url = https://github.com/davisking/dlib.git
10 shallow = true
11 ignore = dirty
12 -[submodule "httpd/h2o"]
13 - path = httpd/h2o
12 +[submodule "web/server/h2o/libh2o"]
13 + path = web/server/h2o/libh2o
14 url = https://github.com/h2o/h2o.git
15 ignore = untracked
CMakeLists.txt
+1 -1
@@ -102,7 +102,7 @@ pkg_check_modules(LIBLZ4 REQUIRED liblz4)
102 set(NETDATA_COMMON_CFLAGS ${NETDATA_COMMON_CFLAGS} ${LIBLZ4_CFLAGS_OTHER})
103 set(NETDATA_COMMON_LIBRARIES ${NETDATA_COMMON_LIBRARIES} ${LIBLZ4_LIBRARIES})
104 set(NETDATA_COMMON_INCLUDE_DIRS ${NETDATA_COMMON_INCLUDE_DIRS} ${LIBLZ4_INCLUDE_DIRS})
105 -# set(NETDATA_REQUIRED_DEFINES "${NETDATA_REQUIRED_DEFINES} -DENABLE_COMPRESSION=1")
105 +# set(NETDATA_REQUIRED_DEFINES "${NETDATA_REQUIRED_DEFINES} -DENABLE_LZ4=1")
106
107 # -----------------------------------------------------------------------------
108 # Judy General purpose dynamic array
Makefile.am
+112 -101
@@ -84,7 +84,7 @@ dist_noinst_DATA = \
84 packaging/protobuf.version \
85 packaging/version \
86 database/engine/journalfile_v2.ksy.in \
87 - httpd/h2o \
87 + web/server/h2o/libh2o \
88 $(NULL)
89
90 # until integrated within build
@@ -281,6 +281,10 @@ CGROUP_NETWORK_FILES = \
281 $(LIBNETDATA_FILES) \
282 $(NULL)
283
284 +LOCAL_LISTENERS_FILES = \
285 + collectors/plugins.d/local_listeners.c \
286 + $(NULL)
287 +
288 DISKSPACE_PLUGIN_FILES = \
289 collectors/diskspace.plugin/plugin_diskspace.c \
290 $(NULL)
@@ -945,111 +949,111 @@ DAEMON_FILES = \
949 daemon/unit_test.h \
950 $(NULL)
951
948 -HTTPD_FILES = \
949 - httpd/http_server.c \
950 - httpd/http_server.h \
951 - httpd/h2o_utils.c \
952 - httpd/h2o_utils.h \
952 +H2O_FILES = \
953 + web/server/h2o/http_server.c \
954 + web/server/h2o/http_server.h \
955 + web/server/h2o/h2o_utils.c \
956 + web/server/h2o/h2o_utils.h \
957 $(NULL)
958
959 libh2o_a_SOURCES = \
956 - httpd/h2o/deps/cloexec/cloexec.c \
957 - httpd/h2o/deps/libgkc/gkc.c \
958 - httpd/h2o/deps/libyrmcds/close.c \
959 - httpd/h2o/deps/libyrmcds/connect.c \
960 - httpd/h2o/deps/libyrmcds/recv.c \
961 - httpd/h2o/deps/libyrmcds/send.c \
962 - httpd/h2o/deps/libyrmcds/send_text.c \
963 - httpd/h2o/deps/libyrmcds/socket.c \
964 - httpd/h2o/deps/libyrmcds/strerror.c \
965 - httpd/h2o/deps/libyrmcds/text_mode.c \
966 - httpd/h2o/deps/picohttpparser/picohttpparser.c \
967 - httpd/h2o/lib/common/cache.c \
968 - httpd/h2o/lib/common/file.c \
969 - httpd/h2o/lib/common/filecache.c \
970 - httpd/h2o/lib/common/hostinfo.c \
971 - httpd/h2o/lib/common/http1client.c \
972 - httpd/h2o/lib/common/memcached.c \
973 - httpd/h2o/lib/common/memory.c \
974 - httpd/h2o/lib/common/multithread.c \
975 - httpd/h2o/lib/common/serverutil.c \
976 - httpd/h2o/lib/common/socket.c \
977 - httpd/h2o/lib/common/socketpool.c \
978 - httpd/h2o/lib/common/string.c \
979 - httpd/h2o/lib/common/time.c \
980 - httpd/h2o/lib/common/timeout.c \
981 - httpd/h2o/lib/common/url.c \
982 - httpd/h2o/lib/core/config.c \
983 - httpd/h2o/lib/core/configurator.c \
984 - httpd/h2o/lib/core/context.c \
985 - httpd/h2o/lib/core/headers.c \
986 - httpd/h2o/lib/core/logconf.c \
987 - httpd/h2o/lib/core/proxy.c \
988 - httpd/h2o/lib/core/request.c \
989 - httpd/h2o/lib/core/token.c \
990 - httpd/h2o/lib/core/util.c \
991 - httpd/h2o/lib/handler/access_log.c \
992 - httpd/h2o/lib/handler/chunked.c \
993 - httpd/h2o/lib/handler/compress.c \
994 - httpd/h2o/lib/handler/compress/gzip.c \
995 - httpd/h2o/lib/handler/errordoc.c \
996 - httpd/h2o/lib/handler/expires.c \
997 - httpd/h2o/lib/handler/fastcgi.c \
998 - httpd/h2o/lib/handler/file.c \
999 - httpd/h2o/lib/handler/headers.c \
1000 - httpd/h2o/lib/handler/mimemap.c \
1001 - httpd/h2o/lib/handler/proxy.c \
1002 - httpd/h2o/lib/handler/redirect.c \
1003 - httpd/h2o/lib/handler/reproxy.c \
1004 - httpd/h2o/lib/handler/throttle_resp.c \
1005 - httpd/h2o/lib/handler/status.c \
1006 - httpd/h2o/lib/handler/headers_util.c \
1007 - httpd/h2o/lib/handler/status/events.c \
1008 - httpd/h2o/lib/handler/status/requests.c \
1009 - httpd/h2o/lib/handler/http2_debug_state.c \
1010 - httpd/h2o/lib/handler/status/durations.c \
1011 - httpd/h2o/lib/handler/configurator/access_log.c \
1012 - httpd/h2o/lib/handler/configurator/compress.c \
1013 - httpd/h2o/lib/handler/configurator/errordoc.c \
1014 - httpd/h2o/lib/handler/configurator/expires.c \
1015 - httpd/h2o/lib/handler/configurator/fastcgi.c \
1016 - httpd/h2o/lib/handler/configurator/file.c \
1017 - httpd/h2o/lib/handler/configurator/headers.c \
1018 - httpd/h2o/lib/handler/configurator/proxy.c \
1019 - httpd/h2o/lib/handler/configurator/redirect.c \
1020 - httpd/h2o/lib/handler/configurator/reproxy.c \
1021 - httpd/h2o/lib/handler/configurator/throttle_resp.c \
1022 - httpd/h2o/lib/handler/configurator/status.c \
1023 - httpd/h2o/lib/handler/configurator/http2_debug_state.c \
1024 - httpd/h2o/lib/handler/configurator/headers_util.c \
1025 - httpd/h2o/lib/http1.c \
1026 - httpd/h2o/lib/tunnel.c \
1027 - httpd/h2o/lib/http2/cache_digests.c \
1028 - httpd/h2o/lib/http2/casper.c \
1029 - httpd/h2o/lib/http2/connection.c \
1030 - httpd/h2o/lib/http2/frame.c \
1031 - httpd/h2o/lib/http2/hpack.c \
1032 - httpd/h2o/lib/http2/scheduler.c \
1033 - httpd/h2o/lib/http2/stream.c \
1034 - httpd/h2o/lib/http2/http2_debug_state.c \
960 + web/server/h2o/libh2o/deps/cloexec/cloexec.c \
961 + web/server/h2o/libh2o/deps/libgkc/gkc.c \
962 + web/server/h2o/libh2o/deps/libyrmcds/close.c \
963 + web/server/h2o/libh2o/deps/libyrmcds/connect.c \
964 + web/server/h2o/libh2o/deps/libyrmcds/recv.c \
965 + web/server/h2o/libh2o/deps/libyrmcds/send.c \
966 + web/server/h2o/libh2o/deps/libyrmcds/send_text.c \
967 + web/server/h2o/libh2o/deps/libyrmcds/socket.c \
968 + web/server/h2o/libh2o/deps/libyrmcds/strerror.c \
969 + web/server/h2o/libh2o/deps/libyrmcds/text_mode.c \
970 + web/server/h2o/libh2o/deps/picohttpparser/picohttpparser.c \
971 + web/server/h2o/libh2o/lib/common/cache.c \
972 + web/server/h2o/libh2o/lib/common/file.c \
973 + web/server/h2o/libh2o/lib/common/filecache.c \
974 + web/server/h2o/libh2o/lib/common/hostinfo.c \
975 + web/server/h2o/libh2o/lib/common/http1client.c \
976 + web/server/h2o/libh2o/lib/common/memcached.c \
977 + web/server/h2o/libh2o/lib/common/memory.c \
978 + web/server/h2o/libh2o/lib/common/multithread.c \
979 + web/server/h2o/libh2o/lib/common/serverutil.c \
980 + web/server/h2o/libh2o/lib/common/socket.c \
981 + web/server/h2o/libh2o/lib/common/socketpool.c \
982 + web/server/h2o/libh2o/lib/common/string.c \
983 + web/server/h2o/libh2o/lib/common/time.c \
984 + web/server/h2o/libh2o/lib/common/timeout.c \
985 + web/server/h2o/libh2o/lib/common/url.c \
986 + web/server/h2o/libh2o/lib/core/config.c \
987 + web/server/h2o/libh2o/lib/core/configurator.c \
988 + web/server/h2o/libh2o/lib/core/context.c \
989 + web/server/h2o/libh2o/lib/core/headers.c \
990 + web/server/h2o/libh2o/lib/core/logconf.c \
991 + web/server/h2o/libh2o/lib/core/proxy.c \
992 + web/server/h2o/libh2o/lib/core/request.c \
993 + web/server/h2o/libh2o/lib/core/token.c \
994 + web/server/h2o/libh2o/lib/core/util.c \
995 + web/server/h2o/libh2o/lib/handler/access_log.c \
996 + web/server/h2o/libh2o/lib/handler/chunked.c \
997 + web/server/h2o/libh2o/lib/handler/compress.c \
998 + web/server/h2o/libh2o/lib/handler/compress/gzip.c \
999 + web/server/h2o/libh2o/lib/handler/errordoc.c \
1000 + web/server/h2o/libh2o/lib/handler/expires.c \
1001 + web/server/h2o/libh2o/lib/handler/fastcgi.c \
1002 + web/server/h2o/libh2o/lib/handler/file.c \
1003 + web/server/h2o/libh2o/lib/handler/headers.c \
1004 + web/server/h2o/libh2o/lib/handler/mimemap.c \
1005 + web/server/h2o/libh2o/lib/handler/proxy.c \
1006 + web/server/h2o/libh2o/lib/handler/redirect.c \
1007 + web/server/h2o/libh2o/lib/handler/reproxy.c \
1008 + web/server/h2o/libh2o/lib/handler/throttle_resp.c \
1009 + web/server/h2o/libh2o/lib/handler/status.c \
1010 + web/server/h2o/libh2o/lib/handler/headers_util.c \
1011 + web/server/h2o/libh2o/lib/handler/status/events.c \
1012 + web/server/h2o/libh2o/lib/handler/status/requests.c \
1013 + web/server/h2o/libh2o/lib/handler/http2_debug_state.c \
1014 + web/server/h2o/libh2o/lib/handler/status/durations.c \
1015 + web/server/h2o/libh2o/lib/handler/configurator/access_log.c \
1016 + web/server/h2o/libh2o/lib/handler/configurator/compress.c \
1017 + web/server/h2o/libh2o/lib/handler/configurator/errordoc.c \
1018 + web/server/h2o/libh2o/lib/handler/configurator/expires.c \
1019 + web/server/h2o/libh2o/lib/handler/configurator/fastcgi.c \
1020 + web/server/h2o/libh2o/lib/handler/configurator/file.c \
1021 + web/server/h2o/libh2o/lib/handler/configurator/headers.c \
1022 + web/server/h2o/libh2o/lib/handler/configurator/proxy.c \
1023 + web/server/h2o/libh2o/lib/handler/configurator/redirect.c \
1024 + web/server/h2o/libh2o/lib/handler/configurator/reproxy.c \
1025 + web/server/h2o/libh2o/lib/handler/configurator/throttle_resp.c \
1026 + web/server/h2o/libh2o/lib/handler/configurator/status.c \
1027 + web/server/h2o/libh2o/lib/handler/configurator/http2_debug_state.c \
1028 + web/server/h2o/libh2o/lib/handler/configurator/headers_util.c \
1029 + web/server/h2o/libh2o/lib/http1.c \
1030 + web/server/h2o/libh2o/lib/tunnel.c \
1031 + web/server/h2o/libh2o/lib/http2/cache_digests.c \
1032 + web/server/h2o/libh2o/lib/http2/casper.c \
1033 + web/server/h2o/libh2o/lib/http2/connection.c \
1034 + web/server/h2o/libh2o/lib/http2/frame.c \
1035 + web/server/h2o/libh2o/lib/http2/hpack.c \
1036 + web/server/h2o/libh2o/lib/http2/scheduler.c \
1037 + web/server/h2o/libh2o/lib/http2/stream.c \
1038 + web/server/h2o/libh2o/lib/http2/http2_debug_state.c \
1039 $(NULL)
1040
1041 libh2o_a_INCLUDES = \
1038 - -I$(srcdir)/httpd/h2o/include \
1039 - -I$(srcdir)/httpd/h2o/deps/cloexec \
1040 - -I$(srcdir)/httpd/h2o/deps/brotli/enc \
1041 - -I$(srcdir)/httpd/h2o/deps/golombset \
1042 - -I$(srcdir)/httpd/h2o/deps/libgkc \
1043 - -I$(srcdir)/httpd/h2o/deps/libyrmcds \
1044 - -I$(srcdir)/httpd/h2o/deps/klib \
1045 - -I$(srcdir)/httpd/h2o/deps/neverbleed \
1046 - -I$(srcdir)/httpd/h2o/deps/picohttpparser \
1047 - -I$(srcdir)/httpd/h2o/deps/picotest \
1048 - -I$(srcdir)/httpd/h2o/deps/yaml/include \
1049 - -I$(srcdir)/httpd/h2o/deps/yoml \
1042 + -I$(srcdir)/web/server/h2o/libh2o/include \
1043 + -I$(srcdir)/web/server/h2o/libh2o/deps/cloexec \
1044 + -I$(srcdir)/web/server/h2o/libh2o/deps/brotli/enc \
1045 + -I$(srcdir)/web/server/h2o/libh2o/deps/golombset \
1046 + -I$(srcdir)/web/server/h2o/libh2o/deps/libgkc \
1047 + -I$(srcdir)/web/server/h2o/libh2o/deps/libyrmcds \
1048 + -I$(srcdir)/web/server/h2o/libh2o/deps/klib \
1049 + -I$(srcdir)/web/server/h2o/libh2o/deps/neverbleed \
1050 + -I$(srcdir)/web/server/h2o/libh2o/deps/picohttpparser \
1051 + -I$(srcdir)/web/server/h2o/libh2o/deps/picotest \
1052 + -I$(srcdir)/web/server/h2o/libh2o/deps/yaml/include \
1053 + -I$(srcdir)/web/server/h2o/libh2o/deps/yoml \
1054 $(NULL)
1055
1052 -if ENABLE_HTTPD
1056 +if ENABLE_H2O
1057 noinst_LIBRARIES += libh2o.a
1058
1059 # until h2o updates support for OpenSSL 3.0 we silence the warnings
@@ -1058,7 +1062,7 @@ libh2o_a_CFLAGS = $(CFLAGS) -Wno-deprecated-declarations -Wno-unused-parameter -
1062 if LINUX
1063 libh2o_a_CFLAGS += -D_GNU_SOURCE
1064 endif
1061 -endif #ENABLE_HTTPD
1065 +endif #ENABLE_H2O
1066
1067 NETDATA_FILES = \
1068 collectors/all.h \
@@ -1129,8 +1133,8 @@ if ENABLE_ACLK
1133 NETDATA_COMMON_LIBS += libmqttwebsockets.a
1134 endif
1135
1132 -if ENABLE_HTTPD
1133 - NETDATA_FILES += $(HTTPD_FILES)
1136 +if ENABLE_H2O
1137 + NETDATA_FILES += $(H2O_FILES)
1138 NETDATA_COMMON_LIBS += libh2o.a
1139 endif
1140
@@ -1205,6 +1209,13 @@ if ENABLE_PLUGIN_CGROUP_NETWORK
1209 $(NULL)
1210 endif
1211
1212 +if ENABLE_PLUGIN_LOCAL_LISTENERS
1213 + plugins_PROGRAMS += local-listeners
1214 + local_listeners_SOURCES = $(LOCAL_LISTENERS_FILES)
1215 + local_listeners_LDADD = \
1216 + $(NULL)
1217 +endif
1218 +
1219 if ENABLE_PLUGIN_FREEIPMI
1220 plugins_PROGRAMS += freeipmi.plugin
1221 freeipmi_plugin_SOURCES = $(FREEIPMI_PLUGIN_FILES)
aclk/aclk.c
+3 -3
@@ -489,15 +489,15 @@ static int aclk_get_transport_idx(aclk_env_t *env) {
489 }
490 #endif
491
492 -ACLK_STATUS aclk_status = ACLK_STATUS_INITIALIZING;
492 +ACLK_STATUS aclk_status = ACLK_STATUS_NONE;
493
494 const char *aclk_status_to_string(void) {
495 switch(aclk_status) {
496 case ACLK_STATUS_CONNECTED:
497 return "connected";
498
499 - case ACLK_STATUS_INITIALIZING:
500 - return "initializing";
499 + case ACLK_STATUS_NONE:
500 + return "none";
501
502 case ACLK_STATUS_DISABLED:
503 return "disabled";
aclk/aclk.h
+1 -1
@@ -15,7 +15,7 @@
15
16 typedef enum __attribute__((packed)) {
17 ACLK_STATUS_CONNECTED = 0,
18 - ACLK_STATUS_INITIALIZING,
18 + ACLK_STATUS_NONE,
19 ACLK_STATUS_DISABLED,
20 ACLK_STATUS_NO_CLOUD_URL,
21 ACLK_STATUS_INVALID_CLOUD_URL,
aclk/aclk_capas.c
+1 -1
@@ -4,7 +4,7 @@
4
5 #include "ml/ml.h"
6
7 -#define HTTP_API_V2_VERSION 4
7 +#define HTTP_API_V2_VERSION 5
8
9 const struct capability *aclk_get_agent_capas()
10 {
claim/claim.c
+272 -14
@@ -42,16 +42,16 @@ char *get_agent_claimid()
42 }
43
44 #define CLAIMING_COMMAND_LENGTH 16384
45 -#define CLAIMING_PROXY_LENGTH CLAIMING_COMMAND_LENGTH/4
45 +#define CLAIMING_PROXY_LENGTH (CLAIMING_COMMAND_LENGTH/4)
46
47 extern struct registry registry;
48
49 /* rrd_init() and post_conf_load() must have been called before this function */
50 -void claim_agent(char *claiming_arguments)
50 +CLAIM_AGENT_RESPONSE claim_agent(const char *claiming_arguments, bool force, const char **msg)
51 {
52 - if (!netdata_cloud_enabled) {
52 + if (!force || !netdata_cloud_enabled) {
53 error("Refusing to claim agent -> cloud functionality has been disabled");
54 - return;
54 + return CLAIM_AGENT_CLOUD_DISABLED;
55 }
56
57 #ifndef DISABLE_CLOUD
@@ -62,8 +62,11 @@ void claim_agent(char *claiming_arguments)
62
63 // This is guaranteed to be set early in main via post_conf_load()
64 char *cloud_base_url = appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", NULL);
65 - if (cloud_base_url == NULL)
66 - fatal("Do not move the cloud base url out of post_conf_load!!");
65 + if (cloud_base_url == NULL) {
66 + internal_fatal(true, "Do not move the cloud base url out of post_conf_load!!");
67 + return CLAIM_AGENT_NO_CLOUD_URL;
68 + }
69 +
70 const char *proxy_str;
71 ACLK_PROXY_TYPE proxy_type;
72 char proxy_flag[CLAIMING_PROXY_LENGTH] = "-noproxy";
@@ -76,7 +79,6 @@ void claim_agent(char *claiming_arguments)
79 snprintfz(command_buffer,
80 CLAIMING_COMMAND_LENGTH,
81 "exec netdata-claim.sh %s -hostname=%s -id=%s -url=%s -noreload %s",
79 -
82 proxy_flag,
83 netdata_configured_hostname,
84 localhost->machine_guid,
@@ -87,7 +89,7 @@ void claim_agent(char *claiming_arguments)
89 fp_child_output = netdata_popen(command_buffer, &command_pid, &fp_child_input);
90 if(!fp_child_output) {
91 error("Cannot popen(\"%s\").", command_buffer);
90 - return;
92 + return CLAIM_AGENT_CANNOT_EXECUTE_CLAIM_SCRIPT;
93 }
94 netdata_log_info("Waiting for claiming command to finish.");
95 while (fgets(command_buffer, CLAIMING_COMMAND_LENGTH, fp_child_output) != NULL) {;}
@@ -95,25 +97,31 @@ void claim_agent(char *claiming_arguments)
97 netdata_log_info("Agent claiming command returned with code %d", exit_code);
98 if (0 == exit_code) {
99 load_claiming_state();
98 - return;
100 + return CLAIM_AGENT_OK;
101 }
102 if (exit_code < 0) {
103 error("Agent claiming command failed to complete its run.");
102 - return;
104 + return CLAIM_AGENT_CLAIM_SCRIPT_FAILED;
105 }
106 errno = 0;
107 unsigned maximum_known_exit_code = sizeof(claiming_errors) / sizeof(claiming_errors[0]) - 1;
108
109 if ((unsigned)exit_code > maximum_known_exit_code) {
110 error("Agent failed to be claimed with an unknown error.");
109 - return;
111 + return CLAIM_AGENT_CLAIM_SCRIPT_RETURNED_INVALID_CODE;
112 }
113 +
114 error("Agent failed to be claimed with the following error message:");
115 error("\"%s\"", claiming_errors[exit_code]);
116 +
117 + if(msg) *msg = claiming_errors[exit_code];
118 +
119 #else
120 UNUSED(claiming_arguments);
121 UNUSED(claiming_errors);
122 #endif
123 +
124 + return CLAIM_AGENT_FAILED_WITH_MESSAGE;
125 }
126
127 #ifdef ENABLE_ACLK
@@ -181,7 +189,7 @@ void load_claiming_state(void)
189 freez(claimed_id);
190
191 netdata_log_info("File '%s' was found. Setting state to AGENT_CLAIMED.", filename);
184 - netdata_cloud_enabled = appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", 1);
192 + netdata_cloud_enabled = appconfig_get_boolean_ondemand(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", netdata_cloud_enabled);
193 #endif
194 }
195
@@ -193,6 +201,10 @@ struct config cloud_config = { .first_section = NULL,
201
202 void load_cloud_conf(int silent)
203 {
204 + char *nd_disable_cloud = getenv("NETDATA_DISABLE_CLOUD");
205 + if (nd_disable_cloud && !strncmp(nd_disable_cloud, "1", 1))
206 + netdata_cloud_enabled = CONFIG_BOOLEAN_NO;
207 +
208 char *filename;
209 errno = 0;
210
@@ -201,8 +213,254 @@ void load_cloud_conf(int silent)
213 filename = strdupz_path_subpath(netdata_configured_varlib_dir, "cloud.d/cloud.conf");
214
215 ret = appconfig_load(&cloud_config, filename, 1, NULL);
204 - if(!ret && !silent) {
216 + if(!ret && !silent)
217 netdata_log_info("CONFIG: cannot load cloud config '%s'. Running with internal defaults.", filename);
206 - }
218 +
219 freez(filename);
220 +
221 + // --------------------------------------------------------------------
222 + // Check if the cloud is enabled
223 +
224 +#if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
225 + netdata_cloud_enabled = CONFIG_BOOLEAN_NO;
226 +#else
227 + netdata_cloud_enabled = appconfig_get_boolean_ondemand(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", netdata_cloud_enabled);
228 +#endif
229 +
230 + // This must be set before any point in the code that accesses it. Do not move it from this function.
231 + appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", DEFAULT_CLOUD_BASE_URL);
232 +}
233 +
234 +static char *netdata_random_session_id_filename = NULL;
235 +static uuid_t netdata_random_session_id = { 0 };
236 +
237 +bool netdata_random_session_id_generate(void) {
238 + static char guid[UUID_STR_LEN] = "";
239 +
240 + uuid_generate_random(netdata_random_session_id);
241 + uuid_unparse_lower(netdata_random_session_id, guid);
242 +
243 + char filename[FILENAME_MAX + 1];
244 + snprintfz(filename, FILENAME_MAX, "%s/netdata_random_session_id", netdata_configured_varlib_dir);
245 +
246 + bool ret = true;
247 +
248 + (void)unlink(filename);
249 +
250 + // save it
251 + int fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 640);
252 + if(fd == -1) {
253 + error("Cannot create random session id file '%s'.", filename);
254 + ret = false;
255 + }
256 +
257 + if(write(fd, guid, UUID_STR_LEN - 1) != UUID_STR_LEN - 1) {
258 + error("Cannot write the random session id file '%s'.", filename);
259 + ret = false;
260 + }
261 +
262 + ssize_t rc = write(fd, "\n", 1);
263 + (void)rc;
264 +
265 + close(fd);
266 +
267 + if(ret && (!netdata_random_session_id_filename || strcmp(netdata_random_session_id_filename, filename) != 0)) {
268 + freez(netdata_random_session_id_filename);
269 + netdata_random_session_id_filename = strdupz(filename);
270 + }
271 +
272 + return ret;
273 +}
274 +
275 +const char *netdata_random_session_id_get_filename(void) {
276 + if(!netdata_random_session_id_filename)
277 + netdata_random_session_id_generate();
278 +
279 + return netdata_random_session_id_filename;
280 +}
281 +
282 +bool netdata_random_session_id_matches(const char *guid) {
283 + if(uuid_is_null(netdata_random_session_id))
284 + return false;
285 +
286 + uuid_t uuid;
287 +
288 + if(uuid_parse(guid, uuid))
289 + return false;
290 +
291 + if(uuid_compare(netdata_random_session_id, uuid) == 0)
292 + return true;
293 +
294 + return false;
295 +}
296 +
297 +static bool check_claim_param(const char *s) {
298 + if(!s || !*s) return true;
299 +
300 + do {
301 + if(isalnum(*s) || *s == '.' || *s == ',' || *s == '-' || *s == ':' || *s == '/' || *s == '_')
302 + ;
303 + else
304 + return false;
305 +
306 + } while(*++s);
307 +
308 + return true;
309 +}
310 +
311 +void claim_reload_all(void) {
312 + error_log_limit_unlimited();
313 + load_claiming_state();
314 + registry_update_cloud_base_url();
315 + rrdpush_send_claimed_id(localhost);
316 + error_log_limit_reset();
317 +}
318 +
319 +int api_v2_claim(struct web_client *w, char *url) {
320 + char *key = NULL;
321 + char *token = NULL;
322 + char *rooms = NULL;
323 + char *base_url = NULL;
324 +
325 + while (url) {
326 + char *value = strsep_skip_consecutive_separators(&url, "&");
327 + if (!value || !*value) continue;
328 +
329 + char *name = strsep_skip_consecutive_separators(&value, "=");
330 + if (!name || !*name) continue;
331 + if (!value || !*value) continue;
332 +
333 + if(!strcmp(name, "key"))
334 + key = value;
335 + else if(!strcmp(name, "token"))
336 + token = value;
337 + else if(!strcmp(name, "rooms"))
338 + rooms = value;
339 + else if(!strcmp(name, "url"))
340 + base_url = value;
341 + }
342 +
343 + BUFFER *wb = w->response.data;
344 + buffer_flush(wb);
345 + buffer_json_initialize(wb, "\"", "\"", 0, true, false);
346 +
347 + time_t now_s = now_realtime_sec();
348 + CLOUD_STATUS status = buffer_json_cloud_status(wb, now_s);
349 +
350 + bool can_be_claimed = false;
351 + switch(status) {
352 + case CLOUD_STATUS_AVAILABLE:
353 + case CLOUD_STATUS_DISABLED:
354 + case CLOUD_STATUS_OFFLINE:
355 + can_be_claimed = true;
356 + break;
357 +
358 + case CLOUD_STATUS_UNAVAILABLE:
359 + case CLOUD_STATUS_BANNED:
360 + case CLOUD_STATUS_ONLINE:
361 + can_be_claimed = false;
362 + break;
363 + }
364 +
365 + buffer_json_member_add_boolean(wb, "can_be_claimed", can_be_claimed);
366 +
367 + if(can_be_claimed && key) {
368 + if(!netdata_random_session_id_matches(key)) {
369 + buffer_reset(wb);
370 + buffer_strcat(wb, "invalid key");
371 + netdata_random_session_id_generate(); // generate a new key, to avoid an attack to find it
372 + return HTTP_RESP_FORBIDDEN;
373 + }
374 +
375 + if(!token || !base_url || !check_claim_param(token) || !check_claim_param(base_url) || (rooms && !check_claim_param(rooms))) {
376 + buffer_reset(wb);
377 + buffer_strcat(wb, "invalid parameters");
378 + netdata_random_session_id_generate(); // generate a new key, to avoid an attack to find it
379 + return HTTP_RESP_BAD_REQUEST;
380 + }
381 +
382 + netdata_random_session_id_generate(); // generate a new key, to avoid an attack to find it
383 +
384 + netdata_cloud_enabled = CONFIG_BOOLEAN_AUTO;
385 + appconfig_set_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", CONFIG_BOOLEAN_AUTO);
386 + appconfig_set(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", base_url);
387 +
388 + uuid_t claimed_id;
389 + uuid_generate_random(claimed_id);
390 + char claimed_id_str[UUID_STR_LEN];
391 + uuid_unparse_lower(claimed_id, claimed_id_str);
392 +
393 + BUFFER *t = buffer_create(1024, NULL);
394 + if(rooms)
395 + buffer_sprintf(t, "-id=%s -token=%s -rooms=%s", claimed_id_str, token, rooms);
396 + else
397 + buffer_sprintf(t, "-id=%s -token=%s", claimed_id_str, token);
398 +
399 + bool success = false;
400 + const char *msg = NULL;
401 + CLAIM_AGENT_RESPONSE rc = claim_agent(buffer_tostring(t), true, &msg);
402 + switch(rc) {
403 + case CLAIM_AGENT_OK:
404 + msg = "ok";
405 + success = true;
406 + can_be_claimed = false;
407 + claim_reload_all();
408 + {
409 + int ms = 0;
410 + do {
411 + status = cloud_status();
412 + if (status == CLOUD_STATUS_ONLINE)
413 + break;
414 +
415 + sleep_usec(100 * USEC_PER_MS);
416 + ms += 100;
417 + } while (ms < 5000);
418 + }
419 + break;
420 +
421 + case CLAIM_AGENT_NO_CLOUD_URL:
422 + msg = "No Netdata Cloud URL.";
423 + break;
424 +
425 + case CLAIM_AGENT_CLAIM_SCRIPT_FAILED:
426 + msg = "Claiming script failed.";
427 + break;
428 +
429 + case CLAIM_AGENT_CLOUD_DISABLED:
430 + msg = "Netdata Cloud is disabled on this agent.";
431 + break;
432 +
433 + case CLAIM_AGENT_CANNOT_EXECUTE_CLAIM_SCRIPT:
434 + msg = "Failed to execute claiming script.";
435 + break;
436 +
437 + case CLAIM_AGENT_CLAIM_SCRIPT_RETURNED_INVALID_CODE:
438 + msg = "Claiming script returned invalid code.";
439 + break;
440 +
441 + default:
442 + case CLAIM_AGENT_FAILED_WITH_MESSAGE:
443 + if(!msg)
444 + msg = "Unknown error";
445 + break;
446 + }
447 +
448 + // our status may have changed
449 + // refresh the status in our output
450 + buffer_flush(wb);
451 + buffer_json_initialize(wb, "\"", "\"", 0, true, false);
452 + now_s = now_realtime_sec();
453 + buffer_json_cloud_status(wb, now_s);
454 +
455 + // and this is the status of the claiming command we run
456 + buffer_json_member_add_boolean(wb, "success", success);
457 + buffer_json_member_add_string(wb, "message", msg);
458 + }
459 +
460 + if(can_be_claimed)
461 + buffer_json_member_add_string(wb, "key_filename", netdata_random_session_id_get_filename());
462 +
463 + buffer_json_finalize(wb);
464 +
465 + return HTTP_RESP_OK;
466 }
claim/claim.h
+17 -1
@@ -8,9 +8,25 @@
8 extern char *claiming_pending_arguments;
9 extern struct config cloud_config;
10
11 -void claim_agent(char *claiming_arguments);
11 +typedef enum __attribute__((packed)) {
12 + CLAIM_AGENT_OK,
13 + CLAIM_AGENT_CLOUD_DISABLED,
14 + CLAIM_AGENT_NO_CLOUD_URL,
15 + CLAIM_AGENT_CANNOT_EXECUTE_CLAIM_SCRIPT,
16 + CLAIM_AGENT_CLAIM_SCRIPT_FAILED,
17 + CLAIM_AGENT_CLAIM_SCRIPT_RETURNED_INVALID_CODE,
18 + CLAIM_AGENT_FAILED_WITH_MESSAGE,
19 +} CLAIM_AGENT_RESPONSE;
20 +
21 +CLAIM_AGENT_RESPONSE claim_agent(const char *claiming_arguments, bool force, const char **msg);
22 char *get_agent_claimid(void);
23 void load_claiming_state(void);
24 void load_cloud_conf(int silent);
25 +void claim_reload_all(void);
26 +
27 +bool netdata_random_session_id_generate(void);
28 +const char *netdata_random_session_id_get_filename(void);
29 +bool netdata_random_session_id_matches(const char *guid);
30 +int api_v2_claim(struct web_client *w, char *url);
31
32 #endif //NETDATA_CLAIM_H
claim/netdata-claim.sh.in
+31 -18
@@ -1,7 +1,7 @@
1 #!/usr/bin/env bash
2 # netdata
3 # real-time performance and health monitoring, done right!
4 -# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
4 +# (C) 2023 Netdata Inc.
5 # SPDX-License-Identifier: GPL-3.0-or-later
6
7 # Exit code: 0 - Success
@@ -194,24 +194,37 @@ if [ -r "${CLAIMING_DIR}/rooms" ]; then
194 ROOMS="$(cat "${CLAIMING_DIR}/rooms")"
195 fi
196
197 +variable_to_set=
198 for arg in "$@"
199 do
199 - case $arg in
200 - -token=*) TOKEN=${arg:7} ;;
201 - -url=*) [ -n "${arg:5}" ] && URL_BASE=${arg:5} ;;
202 - -id=*) ID=$(echo "${arg:4}" | tr '[:upper:]' '[:lower:]');;
203 - -rooms=*) ROOMS=${arg:7} ;;
204 - -hostname=*) HOSTNAME=${arg:10} ;;
205 - -verbose) VERBOSE=1 ;;
206 - -insecure) INSECURE=1 ;;
207 - -proxy=*) PROXY=${arg:7} ;;
208 - -noproxy) NOPROXY=yes ;;
209 - -noreload) RELOAD=0 ;;
210 - -user=*) NETDATA_USER=${arg:6} ;;
211 - -daemon-not-running) NETDATA_RUNNING=0 ;;
212 - *) echo >&2 "Unknown argument ${arg}"
213 - exit 1 ;;
214 - esac
200 + if [ -z "$variable_to_set" ]; then
201 + case $arg in
202 + --claim-token) variable_to_set="TOKEN" ;;
203 + --claim-rooms) variable_to_set="ROOMS" ;;
204 + --claim-url) variable_to_set="URL_BASE" ;;
205 + -token=*) TOKEN=${arg:7} ;;
206 + -url=*) [ -n "${arg:5}" ] && URL_BASE=${arg:5} ;;
207 + -id=*) ID=$(echo "${arg:4}" | tr '[:upper:]' '[:lower:]');;
208 + -rooms=*) ROOMS=${arg:7} ;;
209 + -hostname=*) HOSTNAME=${arg:10} ;;
210 + -verbose) VERBOSE=1 ;;
211 + -insecure) INSECURE=1 ;;
212 + -proxy=*) PROXY=${arg:7} ;;
213 + -noproxy) NOPROXY=yes ;;
214 + -noreload) RELOAD=0 ;;
215 + -user=*) NETDATA_USER=${arg:6} ;;
216 + -daemon-not-running) NETDATA_RUNNING=0 ;;
217 + *) echo >&2 "Unknown argument ${arg}"
218 + exit 1 ;;
219 + esac
220 + else
221 + case "$variable_to_set" in
222 + TOKEN) TOKEN="$arg" ;;
223 + ROOMS) ROOMS="$arg" ;;
224 + URL_BASE) URL_BASE="$arg" ;;
225 + esac
226 + variable_to_set=
227 + fi
228 shift 1
229 done
230
@@ -402,7 +415,7 @@ if [ "${HTTP_STATUS_CODE}" = "204" ] || [ "${ERROR_KEY}" = "ErrAlreadyClaimed" ]
415 cloud base url = $URL_BASE
416 HERE_DOC
417 if [ "$EUID" == "0" ]; then
405 - chown -R "${NETDATA_USER}:${NETDATA_USER}" ${CLAIMING_DIR} || (echo >&2 "Claiming failed"; set -e; exit 2)
418 + chown -R "${NETDATA_USER}:${NETDATA_USER}" "${CLAIMING_DIR}" || (echo >&2 "Claiming failed"; set -e; exit 2)
419 fi
420 if [ "${RELOAD}" == "0" ] ; then
421 exit $EXIT_CODE
collectors/plugins.d/local_listeners.c new
+373
@@ -0,0 +1,373 @@
1 +#include <stdio.h>
2 +#include <stdlib.h>
3 +#include <stdbool.h>
4 +#include <dirent.h>
5 +#include <string.h>
6 +#include <unistd.h>
7 +#include <errno.h>
8 +#include <ctype.h>
9 +#include <arpa/inet.h>
10 +
11 +typedef enum {
12 + PROC_NET_PROTOCOL_TCP,
13 + PROC_NET_PROTOCOL_TCP6,
14 + PROC_NET_PROTOCOL_UDP,
15 + PROC_NET_PROTOCOL_UDP6,
16 +} PROC_NET_PROTOCOLS;
17 +
18 +static inline const char *protocol_name(PROC_NET_PROTOCOLS protocol) {
19 + switch(protocol) {
20 + default:
21 + case PROC_NET_PROTOCOL_TCP:
22 + return "TCP";
23 +
24 + case PROC_NET_PROTOCOL_UDP:
25 + return "UDP";
26 +
27 + case PROC_NET_PROTOCOL_TCP6:
28 + return "TCP6";
29 +
30 + case PROC_NET_PROTOCOL_UDP6:
31 + return "UDP6";
32 + }
33 +}
34 +
35 +#define HASH_TABLE_SIZE 100000
36 +#define MAX_ERROR_LOGS 10
37 +
38 +typedef struct Node {
39 + unsigned int inode;
40 + unsigned int port;
41 + char local_address[INET6_ADDRSTRLEN];
42 + PROC_NET_PROTOCOLS protocol;
43 + bool processed;
44 + struct Node *next;
45 +} Node;
46 +
47 +typedef struct HashTable {
48 + Node *table[HASH_TABLE_SIZE];
49 +} HashTable;
50 +
51 +static size_t pid_fds_processed = 0;
52 +static size_t pid_fds_failed = 0;
53 +static size_t errors_encountered = 0;
54 +
55 +static HashTable *hashTable_key_inode_port_value = NULL;
56 +
57 +static inline void generate_output(const char *protocol, const char *address, unsigned int port, const char *cmdline) {
58 + printf("%s|%s|%u|%s\n", protocol, address, port, cmdline);
59 +}
60 +
61 +HashTable* createHashTable() {
62 + HashTable *hashTable = (HashTable*)malloc(sizeof(HashTable));
63 + memset(hashTable, 0, sizeof(HashTable));
64 + return hashTable;
65 +}
66 +
67 +static inline unsigned int hashFunction(unsigned int inode) {
68 + return inode % HASH_TABLE_SIZE;
69 +}
70 +
71 +static inline void insertHashTable(HashTable *hashTable, unsigned int inode, unsigned int port, PROC_NET_PROTOCOLS protocol, char *local_address) {
72 + unsigned int index = hashFunction(inode);
73 + Node *newNode = (Node*)malloc(sizeof(Node));
74 + newNode->inode = inode;
75 + newNode->port = port;
76 + newNode->protocol = protocol;
77 + strncpy(newNode->local_address, local_address, INET6_ADDRSTRLEN);
78 + newNode->local_address[INET6_ADDRSTRLEN - 1] = '\0';
79 + newNode->next = hashTable->table[index];
80 + hashTable->table[index] = newNode;
81 +}
82 +
83 +static inline unsigned int lookupHashTable(HashTable *hashTable, unsigned int inode, PROC_NET_PROTOCOLS *protocol, char **local_address) {
84 + unsigned int index = hashFunction(inode);
85 + Node *node = hashTable->table[index];
86 + while (node) {
87 + if (node->inode == inode) {
88 + *protocol = node->protocol;
89 + *local_address = node->local_address;
90 + node->processed = true;
91 + return node->port;
92 + }
93 + node = node->next;
94 + }
95 + return 0; // Not found
96 +}
97 +
98 +void freeHashTable(HashTable *hashTable) {
99 + for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++) {
100 + Node *node = hashTable->table[i];
101 + while (node) {
102 + Node *tmp = node;
103 + if(!tmp->processed)
104 + generate_output(protocol_name(tmp->protocol), tmp->local_address, tmp->port, "");
105 + node = node->next;
106 + free(tmp);
107 + }
108 + }
109 + free(hashTable);
110 +}
111 +
112 +static inline int read_cmdline(pid_t pid, char* buffer, size_t bufferSize) {
113 + char path[FILENAME_MAX + 1];
114 + snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
115 + path[FILENAME_MAX] = '\0';
116 +
117 + FILE* file = fopen(path, "r");
118 + if (!file) {
119 + if(++errors_encountered < MAX_ERROR_LOGS)
120 + fprintf(stderr, "local-listeners: error opening file: %s\n", path);
121 +
122 + return -1;
123 + }
124 +
125 + size_t bytesRead = fread(buffer, 1, bufferSize - 1, file);
126 + buffer[bytesRead] = '\0'; // Ensure null-terminated
127 +
128 + // Replace null characters in cmdline with spaces
129 + for (size_t i = 0; i < bytesRead; i++) {
130 + if (buffer[i] == '\0') {
131 + buffer[i] = ' ';
132 + }
133 + }
134 +
135 + fclose(file);
136 + return 0;
137 +}
138 +
139 +static inline void fix_cmdline(char* str) {
140 + if (str == NULL)
141 + return;
142 +
143 + char *s = str;
144 +
145 + do {
146 + if(*s == '|' || iscntrl(*s))
147 + *s = '_';
148 +
149 + } while(*++s);
150 +
151 +
152 + while(s > str && *(s-1) == ' ')
153 + *--s = '\0';
154 +}
155 +
156 +static inline void found_this_socket_inode(pid_t pid, unsigned int inode) {
157 + PROC_NET_PROTOCOLS protocol = 0;
158 + char *address = NULL;
159 + unsigned int port = lookupHashTable(hashTable_key_inode_port_value, inode, &protocol, &address);
160 +
161 + if(port) {
162 + char cmdline[8192] = "";
163 + read_cmdline(pid, cmdline, sizeof(cmdline));
164 + fix_cmdline(cmdline);
165 + generate_output(protocol_name(protocol), address, port, cmdline);
166 + }
167 +}
168 +
169 +bool find_all_sockets_in_proc(const char *proc_filename) {
170 + DIR *proc_dir, *fd_dir;
171 + struct dirent *proc_entry, *fd_entry;
172 + char path_buffer[FILENAME_MAX + 1];
173 +
174 + proc_dir = opendir(proc_filename);
175 + if (proc_dir == NULL) {
176 + if(++errors_encountered < MAX_ERROR_LOGS)
177 + fprintf(stderr, "local-listeners: cannot opendir() '%s' (error: %s)\n", proc_filename, strerror(errno));
178 +
179 + pid_fds_failed++;
180 + return false;
181 + }
182 +
183 + while ((proc_entry = readdir(proc_dir)) != NULL) {
184 + // Check if directory entry is a PID by seeing if the name is made up of digits only
185 + int is_pid = 1;
186 + for (char *c = proc_entry->d_name; *c != '\0'; c++) {
187 + if (*c < '0' || *c > '9') {
188 + is_pid = 0;
189 + break;
190 + }
191 + }
192 +
193 + if (!is_pid)
194 + continue;
195 +
196 + // Build the path to the fd directory of the process
197 + snprintf(path_buffer, FILENAME_MAX, "%s/%s/fd/", proc_filename, proc_entry->d_name);
198 + path_buffer[FILENAME_MAX] = '\0';
199 +
200 + fd_dir = opendir(path_buffer);
201 + if (fd_dir == NULL) {
202 + if(++errors_encountered < MAX_ERROR_LOGS)
203 + fprintf(stderr, "local-listeners: cannot opendir() '%s' (error: %s)\n", path_buffer, strerror(errno));
204 +
205 + pid_fds_failed++;
206 + continue;
207 + }
208 +
209 + while ((fd_entry = readdir(fd_dir)) != NULL) {
210 + if(!strcmp(fd_entry->d_name, ".") || !strcmp(fd_entry->d_name, ".."))
211 + continue;
212 +
213 + char link_path[512];
214 + char link_target[512];
215 + int inode;
216 +
217 + // Build the path to the file descriptor link
218 + strncpy(link_path, path_buffer, sizeof(link_path));
219 + strncat(link_path, fd_entry->d_name, sizeof(link_path) - strlen(link_path) - 1);
220 +
221 + ssize_t len = readlink(link_path, link_target, sizeof(link_target) - 1);
222 + if (len == -1) {
223 + if(++errors_encountered < MAX_ERROR_LOGS)
224 + fprintf(stderr, "local-listeners: cannot read link '%s' (error: %s)\n", link_path, strerror(errno));
225 +
226 + pid_fds_failed++;
227 + continue;
228 + }
229 + link_target[len] = '\0';
230 +
231 + pid_fds_processed++;
232 +
233 + // If the link target indicates a socket, print its inode number
234 + if (sscanf(link_target, "socket:[%d]", &inode) == 1)
235 + found_this_socket_inode((pid_t)strtoul(proc_entry->d_name, NULL, 10), inode);
236 + }
237 +
238 + closedir(fd_dir);
239 + }
240 +
241 + closedir(proc_dir);
242 + return true;
243 +}
244 +
245 +static inline void add_port_and_inode(PROC_NET_PROTOCOLS protocol, unsigned int port, unsigned int inode, char *local_address) {
246 + insertHashTable(hashTable_key_inode_port_value, inode, port, protocol, local_address);
247 +}
248 +
249 +static inline void print_ipv6_address(const char *ipv6_str, char *dst) {
250 + unsigned k;
251 + char buf[9];
252 + struct sockaddr_in6 sa;
253 +
254 + // Initialize sockaddr_in6
255 + memset(&sa, 0, sizeof(struct sockaddr_in6));
256 + sa.sin6_family = AF_INET6;
257 + sa.sin6_port = htons(0); // replace 0 with your port number
258 +
259 + // Convert hex string to byte array
260 + for (k = 0; k < 4; ++k)
261 + {
262 + memset(buf, 0, 9);
263 + memcpy(buf, ipv6_str + (k * 8), 8);
264 + sa.sin6_addr.s6_addr32[k] = strtoul(buf, NULL, 16);
265 + }
266 +
267 + // Convert to human-readable format
268 + if (inet_ntop(AF_INET6, &(sa.sin6_addr), dst, INET6_ADDRSTRLEN) == NULL)
269 + *dst = '\0';
270 +}
271 +
272 +static inline void print_ipv4_address(uint32_t address, char *dst) {
273 + uint8_t octets[4];
274 + octets[0] = address & 0xFF;
275 + octets[1] = (address >> 8) & 0xFF;
276 + octets[2] = (address >> 16) & 0xFF;
277 + octets[3] = (address >> 24) & 0xFF;
278 + sprintf(dst, "%u.%u.%u.%u", octets[0], octets[1], octets[2], octets[3]);
279 +}
280 +
281 +bool read_proc_net_x(const char *filename, PROC_NET_PROTOCOLS protocol) {
282 + FILE *fp;
283 + char *line = NULL;
284 + size_t len = 0;
285 + ssize_t read;
286 + char address[INET6_ADDRSTRLEN];
287 +
288 + ssize_t min_line_length = (protocol == PROC_NET_PROTOCOL_TCP || protocol == PROC_NET_PROTOCOL_UDP) ? 105 : 155;
289 +
290 + fp = fopen(filename, "r");
291 + if (fp == NULL)
292 + return false;
293 +
294 + // Read line by line
295 + while ((read = getline(&line, &len, fp)) != -1) {
296 + if(read < min_line_length) continue;
297 +
298 + char local_address6[33], rem_address6[33];
299 + unsigned int local_address, local_port, state, rem_address, rem_port, inode;
300 +
301 + switch(protocol) {
302 + case PROC_NET_PROTOCOL_TCP:
303 + if(line[34] != '0' || line[35] != 'A')
304 + continue;
305 + // fall-through
306 +
307 + case PROC_NET_PROTOCOL_UDP:
308 + if (sscanf(line, "%*d: %X:%X %X:%X %X %*X:%*X %*X:%*X %*X %*d %*d %u",
309 + &local_address, &local_port, &rem_address, &rem_port, &state, &inode) != 6)
310 + continue;
311 +
312 + print_ipv4_address(local_address, address);
313 + break;
314 +
315 + case PROC_NET_PROTOCOL_TCP6:
316 + if(line[82] != '0' || line[83] != 'A')
317 + continue;
318 + // fall-through
319 +
320 + case PROC_NET_PROTOCOL_UDP6:
321 + if(sscanf(line, "%*d: %32[0-9A-Fa-f]:%X %32[0-9A-Fa-f]:%X %X %*X:%*X %*X:%*X %*X %*d %*d %u",
322 + local_address6, &local_port, rem_address6, &rem_port, &state, &inode) != 6)
323 + continue;
324 +
325 + print_ipv6_address(local_address6, address);
326 + break;
327 + }
328 +
329 + add_port_and_inode(protocol, local_port, inode, address);
330 + }
331 +
332 + fclose(fp);
333 + if (line)
334 + free(line);
335 +
336 + return true;
337 +}
338 +
339 +int main(int argc, char **argv) {
340 + (void)argc;
341 + (void)argv;
342 +
343 + char *netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
344 + if(!netdata_configured_host_prefix) netdata_configured_host_prefix = "";
345 +
346 + char path[FILENAME_MAX + 1];
347 +
348 + hashTable_key_inode_port_value = createHashTable();
349 +
350 + snprintf(path, FILENAME_MAX, "%s/proc/net/tcp", netdata_configured_host_prefix);
351 + path[FILENAME_MAX] = '\0';
352 + read_proc_net_x(path, PROC_NET_PROTOCOL_TCP);
353 +
354 + snprintf(path, FILENAME_MAX, "%s/proc/net/udp", netdata_configured_host_prefix);
355 + path[FILENAME_MAX] = '\0';
356 + read_proc_net_x(path, PROC_NET_PROTOCOL_UDP);
357 +
358 + snprintf(path, FILENAME_MAX, "%s/proc/net/tcp6", netdata_configured_host_prefix);
359 + path[FILENAME_MAX] = '\0';
360 + read_proc_net_x(path, PROC_NET_PROTOCOL_TCP6);
361 +
362 + snprintf(path, FILENAME_MAX, "%s/proc/net/udp6", netdata_configured_host_prefix);
363 + path[FILENAME_MAX] = '\0';
364 + read_proc_net_x(path, PROC_NET_PROTOCOL_UDP6);
365 +
366 + snprintf(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
367 + path[FILENAME_MAX] = '\0';
368 + find_all_sockets_in_proc(path);
369 +
370 + freeHashTable(hashTable_key_inode_port_value);
371 +
372 + return 0;
373 +}
collectors/plugins.d/plugins_d.c
+1 -1
@@ -3,7 +3,7 @@
3 #include "plugins_d.h"
4 #include "pluginsd_parser.h"
5
6 -char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { NULL };
6 +char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { [0] = PLUGINS_DIR, };
7 struct plugind *pluginsd_root = NULL;
8
9 inline size_t pluginsd_initialize_plugin_directories()
configure.ac
+75 -56
@@ -154,16 +154,16 @@ AC_ARG_ENABLE(
154 [enable_lto="no"]
155 )
156 AC_ARG_ENABLE(
157 - [https],
158 - [AS_HELP_STRING([--enable-https], [Enable SSL support @<:@default autodetect@:>@])],
157 + [openssl],
158 + [AS_HELP_STRING([--enable-openssl], [Enable OpenSSL support @<:@default autodetect@:>@])],
159 ,
160 - [enable_https="detect"]
160 + [enable_openssl="detect"]
161 )
162 AC_ARG_ENABLE(
163 - [compression],
164 - [AS_HELP_STRING([--enable-compression], [Enable LZ4 compression support @<:@default autodetect@:>@])],
163 + [lz4],
164 + [AS_HELP_STRING([--enable-lz4], [Enable LZ4 support @<:@default autodetect@:>@])],
165 ,
166 - [enable_compression="detect"]
166 + [enable_lz4="detect"]
167 )
168 AC_ARG_ENABLE(
169 [dbengine],
@@ -208,10 +208,10 @@ AC_ARG_ENABLE(
208 [aclk_ssl_debug="no"]
209 )
210 AC_ARG_ENABLE(
211 - [httpd],
212 - [AS_HELP_STRING([--disable-httpd], [Disable webserver (h2o based) @<:@default autodetect@:>@])],
211 + [h2o],
212 + [AS_HELP_STRING([--disable-h2o], [Disable H2O webserver @<:@default autodetect@:>@])],
213 ,
214 - [enable_httpd="detect"]
214 + [enable_h2o="detect"]
215 )
216
217 # -----------------------------------------------------------------------------
@@ -373,8 +373,25 @@ darwin*)
373 esac
374
375 AM_CONDITIONAL([FREEBSD], [test "${build_target}" = "freebsd"])
376 +if test "${build_target}" = "freebsd"
377 +then
378 + AC_DEFINE([COMPILED_FOR_FREEBSD], [1], [Compiled for FreeBSD])
379 +fi
380 +
381 AM_CONDITIONAL([MACOS], [test "${build_target}" = "macos"])
382 +if test "${build_target}" = "macos"
383 +then
384 + AC_DEFINE([COMPILED_FOR_MACOS], [1], [Compiled for MacOS])
385 +fi
386 +
387 AM_CONDITIONAL([LINUX], [test "${build_target}" = "linux"])
388 +if test "${build_target}" = "linux"
389 +then
390 + AC_DEFINE([COMPILED_FOR_LINUX], [1], [Compiled for Linux])
391 +fi
392 +
393 +AM_CONDITIONAL([ENABLE_PLUGIN_LOCAL_LISTENERS], [test "${build_target}" = "linux"])
394 +
395 AC_MSG_RESULT([Host OS: ${build_target}])
396
397 # -----------------------------------------------------------------------------
@@ -382,7 +399,7 @@ AC_MSG_RESULT([Host OS: ${build_target}])
399
400 HARDENING_CFLAGS=""
401
385 -if ! echo "${originalCFLAGS}" | grep -q '-fstack-protector'; then
402 +if ! echo "${originalCFLAGS}" | grep -q '\-fstack-protector'; then
403 AX_CHECK_COMPILE_FLAG(
404 [-fstack-protector-strong],
405 [HARDENING_CFLAGS="${HARDENING_CFLAGS} -fstack-protector-strong"],
@@ -396,7 +413,7 @@ if ! echo "${originalCFLAGS}" | grep -q '-fstack-protector'; then
413 )
414 fi
415
399 -if ! echo "${originalCFLAGS}" | grep -q '-fno-stack-clash-protection'; then
416 +if ! echo "${originalCFLAGS}" | grep -q '\-fno-stack-clash-protection'; then
417 AX_CHECK_COMPILE_FLAG(
418 [-fstack-clash-protection],
419 [HARDENING_CFLAGS="${HARDENING_CFLAGS} -fstack-clash-protection"],
@@ -405,7 +422,7 @@ if ! echo "${originalCFLAGS}" | grep -q '-fno-stack-clash-protection'; then
422 )
423 fi
424
408 -if ! echo "${originalCFLAGS}" | grep -q '-fcf-protection'; then
425 +if ! echo "${originalCFLAGS}" | grep -q '\-fcf-protection'; then
426 AX_CHECK_COMPILE_FLAG(
427 [-fcf-protection=full],
428 [HARDENING_CFLAGS="${HARDENING_CFLAGS} -fcf-protection=full"],
@@ -414,7 +431,7 @@ if ! echo "${originalCFLAGS}" | grep -q '-fcf-protection'; then
431 )
432 fi
433
417 -if ! echo "${originalCFLAGS}" | grep -q '-mbranch-protection'; then
434 +if ! echo "${originalCFLAGS}" | grep -q '\-mbranch-protection'; then
435 AX_CHECK_COMPILE_FLAG(
436 [-mbranch-protection=standard],
437 [HARDENING_CFLAGS="${HARDENING_CFLAGS} -mbranch-protection=standard"],
@@ -423,7 +440,7 @@ if ! echo "${originalCFLAGS}" | grep -q '-mbranch-protection'; then
440 )
441 fi
442
426 -if ! echo "${originalCFLAGS}" | grep -q '-D_FORTIFY_SOURCE'; then
443 +if ! echo "${originalCFLAGS}" | grep -q '\-D_FORTIFY_SOURCE'; then
444 # This complex set of checks is needed because there is no clean
445 # way to verify _FORTIFY_SOURCE support without having to check for
446 # the required compiler builtins.
@@ -434,7 +451,7 @@ if ! echo "${originalCFLAGS}" | grep -q '-D_FORTIFY_SOURCE'; then
451 [HAVE_FORTIFY_SOURCE=2]
452 )
453
437 - if test "x${HAVE_FORTIFY_SOURCE}" = "x2" && echo "${originalCFLAGS}" | grep -qv '-O0'; then
454 + if test "x${HAVE_FORTIFY_SOURCE}" = "x2" && echo "${originalCFLAGS}" | grep -qv '\-O0'; then
455 AC_CHECK_DECL(
456 __builtin_dynamic_object_size,
457 [AX_CHECK_COMPILE_FLAG(
@@ -528,7 +545,7 @@ OPTIONAL_UV_LIBS="${UV_LIBS}"
545
546
547 # -----------------------------------------------------------------------------
531 -# lz4 Extremely Fast Compression algorithm
548 +# lz4
549
550 AC_CHECK_LIB(
551 [lz4],
@@ -617,7 +634,8 @@ AC_CHECK_LIB(
634 OPTIONAL_YAML_LIBS="${YAML_LIBS}"
635
636 # -----------------------------------------------------------------------------
620 -# DB engine and HTTPS
637 +# DB engine and OpenSSL
638 +
639 test "${enable_dbengine}" = "yes" -a -z "${LZ4_LIBS}" && \
640 AC_MSG_ERROR([liblz4 required but not found. Try installing 'liblz4-dev' or 'lz4-devel'.])
641
@@ -638,8 +656,8 @@ AC_SUBST([LIBJUDY_CFLAGS])
656
657 JUDY_CFLAGS="-I \$(abs_top_srcdir)/libnetdata/libjudy/src"
658
641 -test "${enable_https}" = "yes" -a -z "${SSL_LIBS}" && \
642 - AC_MSG_ERROR([OpenSSL required for HTTPS but not found. Try installing 'libssl-dev' or 'openssl-devel'.])
659 +test "${enable_openssl}" = "yes" -a -z "${SSL_LIBS}" && \
660 + AC_MSG_ERROR([OpenSSL required but not found. Try installing 'libssl-dev' or 'openssl-devel'.])
661
662 test "${enable_dbengine}" = "yes" -a -z "${SSL_LIBS}" && \
663 AC_MSG_ERROR([OpenSSL required for DBENGINE but not found. Try installing 'libssl-dev' or 'openssl-devel'.])
@@ -658,20 +676,20 @@ fi
676 AC_MSG_RESULT([${enable_dbengine}])
677 AM_CONDITIONAL([ENABLE_DBENGINE], [test "${enable_dbengine}" = "yes"])
678
661 -AC_MSG_CHECKING([if netdata https should be used])
662 -if test "${enable_https}" != "no" -a "${SSL_LIBS}"; then
663 - enable_https="yes"
664 - AC_DEFINE([ENABLE_HTTPS], [1], [netdata HTTPS usability])
679 +AC_MSG_CHECKING([if openssl should be used])
680 +if test "${enable_openssl}" != "no" -a "${SSL_LIBS}"; then
681 + enable_openssl="yes"
682 + AC_DEFINE([ENABLE_OPENSSL], [1], [openssl usability])
683 OPTIONAL_SSL_CFLAGS="${SSL_CFLAGS}"
684 OPTIONAL_SSL_LIBS="${SSL_LIBS}"
685 else
668 - enable_https="no"
686 + enable_openssl="no"
687 fi
670 -AC_MSG_RESULT([${enable_https}])
671 -AM_CONDITIONAL([ENABLE_HTTPS], [test "${enable_https}" = "yes"])
688 +AC_MSG_RESULT([${enable_openssl}])
689 +AM_CONDITIONAL([ENABLE_OPENSSL], [test "${enable_openssl}" = "yes"])
690
673 -AC_MSG_CHECKING([if netdata compression should be used])
674 -if test "${enable_compression}" != "no"; then
691 +AC_MSG_CHECKING([if lz4 should be used])
692 +if test "${enable_lz4}" != "no"; then
693 if test "${LZ4_LIBS_FAST}"; then
694 LIBS_BKP="${LIBS}"
695 LIBS="${LZ4_LIBS_FAST}"
@@ -680,26 +698,26 @@ if test "${enable_compression}" != "no"; then
698 [
699 LZ4_stream_t* stream = LZ4_initStream(NULL, 0);
700 ],
683 - [ enable_compression="yes"],
684 - [ enable_compression="no" ]
701 + [ enable_lz4="yes"],
702 + [ enable_lz4="no" ]
703 )
704 LIBS="${LIBS_BKP}"
687 - if test "${enable_compression}" == "yes"; then
705 + if test "${enable_lz4}" == "yes"; then
706 OPTIONAL_LZ4_LIBS="${LZ4_LIBS_FAST}"
689 - AC_DEFINE([ENABLE_COMPRESSION], [1], [netdata compression usability])
707 + AC_DEFINE([ENABLE_LZ4], [1], [lz4 usability])
708 fi
709 else
692 - if test "${enable_compression}" == "yes"; then
693 - AC_MSG_ERROR([liblz4 with version >= 1.9.0 required to enable_compression. Try installing the required version of 'liblz4-dev' or 'liblz4-devel'.])
694 - enable_compression="no"
710 + if test "${enable_lz4}" == "yes"; then
711 + AC_MSG_ERROR([liblz4 with version >= 1.9.0 required to enable lz4. Try installing the required version of 'liblz4-dev' or 'liblz4-devel'.])
712 + enable_lz4="no"
713 fi
696 - enable_compression="no"
714 + enable_lz4="no"
715 fi
716 else
699 - enable_compression="no"
717 + enable_lz4="no"
718 fi
701 -AC_MSG_RESULT([${enable_compression}])
702 -AM_CONDITIONAL([ENABLE_COMPRESSION], [test "${enable_compression}" = "yes"])
719 +AC_MSG_RESULT([${enable_lz4}])
720 +AM_CONDITIONAL([ENABLE_LZ4], [test "${enable_lz4}" = "yes"])
721
722 # -----------------------------------------------------------------------------
723 # JSON-C
@@ -864,36 +882,36 @@ AC_MSG_RESULT([${with_libcap}])
882 AM_CONDITIONAL([ENABLE_CAPABILITY], [test "${with_libcap}" = "yes"])
883
884 # -----------------------------------------------------------------------------
867 -# HTTPD and h2o related
885 +# H2O related
886
869 -can_build_httpd="no"
870 -if test "${enable_httpd}" != "no"; then
871 - can_build_httpd="yes"
872 - AC_MSG_CHECKING([can build HTTPD])
887 +can_build_h2o="no"
888 +if test "${enable_h2o}" != "no"; then
889 + can_build_h2o="yes"
890 + AC_MSG_CHECKING([can build H2O])
891 if test -z "${UV_LIBS}"; then
874 - can_build_httpd="no"
892 + can_build_h2o="no"
893 fi
894 if test -n "${SSL_LIBS}"; then
895 OPTIONAL_SSL_CFLAGS="${SSL_CFLAGS}"
896 OPTIONAL_SSL_LIBS="${SSL_LIBS}"
897 else
880 - can_build_httpd="no"
898 + can_build_h2o="no"
899 fi
900 if test "${with_zlib}" != "yes"; then
883 - can_build_httpd="no"
901 + can_build_h2o="no"
902 fi
885 - AC_MSG_RESULT([${can_build_httpd}])
903 + AC_MSG_RESULT([${can_build_h2o}])
904
887 - if test "${can_build_httpd}" = "no" -a "${enable_httpd}" = "yes"; then
888 - AC_MSG_ERROR([HTTPD was requested but it cannot be built])
905 + if test "${can_build_h2o}" = "no" -a "${enable_h2o}" = "yes"; then
906 + AC_MSG_ERROR([H2O was requested but it cannot be built])
907 fi
908
891 - if test "${can_build_httpd}" = "yes"; then
892 - AC_DEFINE([ENABLE_HTTPD], [1], [HTTPD (h2o based web server)])
893 - HTTPD_CFLAGS="-I\$(abs_top_srcdir)/httpd/h2o/include -I\$(abs_top_srcdir)/httpd/h2o/deps/picotls/include -I\$(abs_top_srcdir)/httpd/h2o/deps/quicly/include -DH2O_USE_LIBUV=0"
909 + if test "${can_build_h2o}" = "yes"; then
910 + AC_DEFINE([ENABLE_H2O], [1], [H2O web server])
911 + H2O_CFLAGS="-I\$(abs_top_srcdir)/web/server/h2o/libh2o/include -I\$(abs_top_srcdir)/web/server/h2o/libh2o/deps/picotls/include -I\$(abs_top_srcdir)/web/server/h2o/libh2o/deps/quicly/include -DH2O_USE_LIBUV=0"
912 fi
913 fi
896 -AM_CONDITIONAL([ENABLE_HTTPD], [test "${can_build_httpd}" = "yes"])
914 +AM_CONDITIONAL([ENABLE_H2O], [test "${can_build_h2o}" = "yes"])
915
916 # -----------------------------------------------------------------------------
917 # ACLK
@@ -1165,7 +1183,6 @@ PKG_CHECK_MODULES(
1183 [have_libmnl=no]
1184 )
1185
1168 -
1186 LIBS="${LIBS}"
1187
1188 PKG_CHECK_MODULES(
@@ -1341,6 +1358,7 @@ AC_MSG_CHECKING([if git submodules are present for machine learning functionalit
1358 if test -f "ml/dlib/dlib/all/source.cpp"; then
1359 AC_MSG_RESULT([yes])
1360 have_ml_submodules="yes"
1361 + AC_DEFINE([HAVE_DLIB], [1], [dlib availability])
1362 else
1363 AC_MSG_RESULT([no])
1364 have_ml_submodules="no"
@@ -1800,7 +1818,7 @@ CFLAGS="${originalCFLAGS} ${OPTIONAL_LTO_CFLAGS} ${OPTIONAL_PROTOBUF_CFLAGS} ${O
1818 ${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS} ${OPTIONAL_CUPS_CFLAGS} ${OPTIONAL_XENSTAT_FLAGS} \
1819 ${OPTIONAL_KINESIS_CFLAGS} ${OPTIONAL_PUBSUB_CFLAGS} ${OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS} \
1820 ${OPTIONAL_MONGOC_CFLAGS} ${LWS_CFLAGS} ${OPTIONAL_JSONC_STATIC_CFLAGS} ${OPTIONAL_YAML_STATIC_CFLAGS} ${OPTIONAL_BPF_CFLAGS} ${JUDY_CFLAGS} \
1803 - ${OPTIONAL_ACLK_CFLAGS} ${OPTIONAL_ML_CFLAGS} ${OPTIONAL_OS_DEP_CFLAGS} ${HTTPD_CFLAGS} ${HARDENING_CFLAGS}"
1821 + ${OPTIONAL_ACLK_CFLAGS} ${OPTIONAL_ML_CFLAGS} ${OPTIONAL_OS_DEP_CFLAGS} ${H2O_CFLAGS} ${HARDENING_CFLAGS}"
1822
1823 CXXFLAGS="${CFLAGS} ${OPTIONAL_KINESIS_CXXFLAGS} ${CPP_STD_FLAG}"
1824
@@ -1886,6 +1904,7 @@ AC_SUBST([TEST_LIBS])
1904
1905 # -----------------------------------------------------------------------------
1906 # save configure options for build info
1907 +
1908 AC_DEFINE_UNQUOTED(
1909 [CONFIGURE_COMMAND],
1910 ["$ac_configure_args"],
contrib/debian/netdata.postinst
+1
@@ -42,6 +42,7 @@ case "$1" in
42 grep /usr/libexec/netdata /var/lib/dpkg/info/netdata.list | xargs -n 30 chown root:netdata
43
44 chmod 4750 /usr/libexec/netdata/plugins.d/cgroup-network
45 + chmod 4750 /usr/libexec/netdata/plugins.d/local-listeners
46
47 # Workaround for other plugins not installed directly by this package
48 chmod -f 4750 /usr/libexec/netdata/plugins.d/ioping || true
contrib/debian/rules
+6
@@ -207,6 +207,12 @@ override_dh_fixperms:
207 # NFACCT plugin package
208 chmod 4750 $(TOP)-plugin-nfacct/usr/libexec/netdata/plugins.d/nfacct.plugin
209
210 + # cgroup-network
211 + chmod 4750 $(TOP)/usr/libexec/netdata/plugins.d/cgroup-network
212 +
213 + # local-listeners
214 + chmod 4750 $(TOP)/usr/libexec/netdata/plugins.d/local-listeners
215 +
216 override_dh_installlogrotate:
217 cp system/logrotate/netdata debian/netdata.logrotate
218 dh_installlogrotate
coverity-scan.sh
+2 -1
@@ -173,7 +173,8 @@ installit() {
173 OTHER_OPTIONS="--disable-lto"
174 OTHER_OPTIONS+=" --with-zlib"
175 OTHER_OPTIONS+=" --with-math"
176 -OTHER_OPTIONS+=" --enable-https"
176 +OTHER_OPTIONS+=" --enable-lz4"
177 +OTHER_OPTIONS+=" --enable-openssl"
178 OTHER_OPTIONS+=" --enable-jsonc"
179 OTHER_OPTIONS+=" --enable-plugin-nfacct"
180 OTHER_OPTIONS+=" --enable-plugin-freeipmi"
daemon/analytics.c
+1 -1
@@ -657,7 +657,7 @@ void set_late_global_environment(struct rrdhost_system_info *system_info)
657 #else
658 analytics_set_data(
659 &analytics_data.netdata_host_cloud_enabled,
660 - appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", CONFIG_BOOLEAN_YES) ? "true" : "false");
660 + appconfig_get_boolean_ondemand(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", netdata_cloud_enabled) ? "true" : "false");
661 #endif
662
663 #ifdef ENABLE_DBENGINE
daemon/buildinfo.c
+1372 -355
@@ -5,209 +5,1301 @@
5 #include "common.h"
6 #include "buildinfo.h"
7
8 -// Optional features
8 +typedef enum __attribute__((packed)) {
9 + BIB_PACKAGING_NETDATA_VERSION,
10 + BIB_PACKAGING_INSTALL_TYPE,
11 + BIB_PACKAGING_ARCHITECTURE,
12 + BIB_PACKAGING_DISTRO,
13 + BIB_PACKAGING_CONFIGURE_OPTIONS,
14 + BIB_DIR_USER_CONFIG,
15 + BIB_DIR_STOCK_CONFIG,
16 + BIB_DIR_CACHE,
17 + BIB_DIR_LIB,
18 + BIB_DIR_PLUGINS,
19 + BIB_DIR_WEB,
20 + BIB_DIR_LOG,
21 + BIB_DIR_LOCK,
22 + BIB_DIR_HOME,
23 + BIB_OS_KERNEL_NAME,
24 + BIB_OS_KERNEL_VERSION,
25 + BIB_OS_NAME,
26 + BIB_OS_ID,
27 + BIB_OS_ID_LIKE,
28 + BIB_OS_VERSION,
29 + BIB_OS_VERSION_ID,
30 + BIB_OS_DETECTION,
31 + BIB_HW_CPU_CORES,
32 + BIB_HW_CPU_FREQUENCY,
33 + BIB_HW_RAM_SIZE,
34 + BIB_HW_DISK_SPACE,
35 + BIB_HW_ARCHITECTURE,
36 + BIB_HW_VIRTUALIZATION,
37 + BIB_HW_VIRTUALIZATION_DETECTION,
38 + BIB_CONTAINER_NAME,
39 + BIB_CONTAINER_DETECTION,
40 + BIB_CONTAINER_ORCHESTRATOR,
41 + BIB_CONTAINER_OS_NAME,
42 + BIB_CONTAINER_OS_ID,
43 + BIB_CONTAINER_OS_ID_LIKE,
44 + BIB_CONTAINER_OS_VERSION,
45 + BIB_CONTAINER_OS_VERSION_ID,
46 + BIB_CONTAINER_OS_DETECTION,
47 + BIB_FEATURE_BUILT_FOR,
48 + BIB_FEATURE_CLOUD,
49 + BIB_FEATURE_HEALTH,
50 + BIB_FEATURE_STREAMING,
51 + BIB_FEATURE_REPLICATION,
52 + BIB_FEATURE_STREAMING_COMPRESSION,
53 + BIB_FEATURE_CONTEXTS,
54 + BIB_FEATURE_TIERING,
55 + BIB_FEATURE_ML,
56 + BIB_DB_DBENGINE,
57 + BIB_DB_ALLOC,
58 + BIB_DB_RAM,
59 + BIB_DB_MAP,
60 + BIB_DB_SAVE,
61 + BIB_DB_NONE,
62 + BIB_CONNECTIVITY_ACLK,
63 + BIB_CONNECTIVITY_HTTPD_STATIC,
64 + BIB_CONNECTIVITY_HTTPD_H2O,
65 + BIB_CONNECTIVITY_WEBRTC,
66 + BIB_CONNECTIVITY_NATIVE_HTTPS,
67 + BIB_CONNECTIVITY_TLS_HOST_VERIFY,
68 + BIB_LIB_LZ4,
69 + BIB_LIB_ZLIB,
70 + BIB_LIB_JUDY,
71 + BIB_LIB_DLIB,
72 + BIB_LIB_PROTOBUF,
73 + BIB_LIB_OPENSSL,
74 + BIB_LIB_LIBDATACHANNEL,
75 + BIB_LIB_JSONC,
76 + BIB_LIB_LIBCAP,
77 + BIB_LIB_LIBCRYPTO,
78 + BIB_LIB_LIBM,
79 + BIB_LIB_JEMALLOC,
80 + BIB_LIB_TCMALLOC,
81 + BIB_PLUGIN_APPS,
82 + BIB_PLUGIN_LINUX_CGROUPS,
83 + BIB_PLUGIN_LINUX_CGROUP_NETWORK,
84 + BIB_PLUGIN_LINUX_PROC,
85 + BIB_PLUGIN_LINUX_TC,
86 + BIB_PLUGIN_LINUX_DISKSPACE,
87 + BIB_PLUGIN_FREEBSD,
88 + BIB_PLUGIN_MACOS,
89 + BIB_PLUGIN_STATSD,
90 + BIB_PLUGIN_TIMEX,
91 + BIB_PLUGIN_IDLEJITTER,
92 + BIB_PLUGIN_BASH,
93 + BIB_PLUGIN_DEBUGFS,
94 + BIB_PLUGIN_CUPS,
95 + BIB_PLUGIN_EBPF,
96 + BIB_PLUGIN_FREEIPMI,
97 + BIB_PLUGIN_NFACCT,
98 + BIB_PLUGIN_PERF,
99 + BIB_PLUGIN_SLABINFO,
100 + BIB_PLUGIN_XEN,
101 + BIB_PLUGIN_XEN_VBD_ERROR,
102 + BIB_EXPORT_AWS_KINESIS,
103 + BIB_EXPORT_GCP_PUBSUB,
104 + BIB_EXPORT_MONGOC,
105 + BIB_EXPORT_PROMETHEUS_EXPORTER,
106 + BIB_EXPORT_PROMETHEUS_REMOTE_WRITE,
107 + BIB_EXPORT_GRAPHITE,
108 + BIB_EXPORT_GRAPHITE_HTTP,
109 + BIB_EXPORT_JSON,
110 + BIB_EXPORT_JSON_HTTP,
111 + BIB_EXPORT_OPENTSDB,
112 + BIB_EXPORT_OPENTSDB_HTTP,
113 + BIB_EXPORT_ALLMETRICS,
114 + BIB_EXPORT_SHELL,
115 + BIB_DEVEL_TRACE_ALLOCATIONS,
116 + BIB_DEVELOPER_MODE,
117 +
118 + // leave this last
119 + BIB_TERMINATOR,
120 +} BUILD_INFO_SLOT;
121 +
122 +typedef enum __attribute__((packed)) {
123 + BIC_PACKAGING,
124 + BIC_DIRECTORIES,
125 + BIC_OPERATING_SYSTEM,
126 + BIC_HARDWARE,
127 + BIC_CONTAINER,
128 + BIC_FEATURE,
129 + BIC_DATABASE,
130 + BIC_CONNECTIVITY,
131 + BIC_LIBS,
132 + BIC_PLUGINS,
133 + BIC_EXPORTERS,
134 + BIC_DEBUG_DEVEL
135 +} BUILD_INFO_CATEGORY;
136 +
137 +typedef enum __attribute__((packed)) {
138 + BIT_BOOLEAN,
139 + BIT_STRING,
140 +} BUILD_INFO_TYPE;
141 +
142 +static struct {
143 + BUILD_INFO_CATEGORY category;
144 + BUILD_INFO_TYPE type;
145 + const char *analytics;
146 + const char *print;
147 + const char *json;
148 + bool status;
149 + const char *value;
150 +} BUILD_INFO[] = {
151 + [BIB_PACKAGING_NETDATA_VERSION] = {
152 + .category = BIC_PACKAGING,
153 + .type = BIT_STRING,
154 + .analytics = NULL,
155 + .print = "Netdata Version",
156 + .json = "version",
157 + .value = "unknown",
158 + },
159 + [BIB_PACKAGING_INSTALL_TYPE] = {
160 + .category = BIC_PACKAGING,
161 + .type = BIT_STRING,
162 + .analytics = NULL,
163 + .print = "Installation Type",
164 + .json = "type",
165 + .value = "unknown",
166 + },
167 + [BIB_PACKAGING_ARCHITECTURE] = {
168 + .category = BIC_PACKAGING,
169 + .type = BIT_STRING,
170 + .analytics = NULL,
171 + .print = "Package Architecture",
172 + .json = "arch",
173 + .value = "unknown",
174 + },
175 + [BIB_PACKAGING_DISTRO] = {
176 + .category = BIC_PACKAGING,
177 + .type = BIT_STRING,
178 + .analytics = NULL,
179 + .print = "Package Distro",
180 + .json = "distro",
181 + .value = "unknown",
182 + },
183 + [BIB_PACKAGING_CONFIGURE_OPTIONS] = {
184 + .category = BIC_PACKAGING,
185 + .type = BIT_STRING,
186 + .analytics = NULL,
187 + .print = "Configure Options",
188 + .json = "configure",
189 + .value = "unknown",
190 + },
191 + [BIB_DIR_USER_CONFIG] = {
192 + .category = BIC_DIRECTORIES,
193 + .type = BIT_STRING,
194 + .analytics = NULL,
195 + .print = "User Configurations",
196 + .json = "user_config",
197 + .value = CONFIG_DIR,
198 + },
199 + [BIB_DIR_STOCK_CONFIG] = {
200 + .category = BIC_DIRECTORIES,
201 + .type = BIT_STRING,
202 + .analytics = NULL,
203 + .print = "Stock Configurations",
204 + .json = "stock_config",
205 + .value = LIBCONFIG_DIR,
206 + },
207 + [BIB_DIR_CACHE] = {
208 + .category = BIC_DIRECTORIES,
209 + .type = BIT_STRING,
210 + .analytics = NULL,
211 + .print = "Ephemeral Databases (metrics data, metadata)",
212 + .json = "ephemeral_db",
213 + .value = CACHE_DIR,
214 + },
215 + [BIB_DIR_LIB] = {
216 + .category = BIC_DIRECTORIES,
217 + .type = BIT_STRING,
218 + .analytics = NULL,
219 + .print = "Permanent Databases",
220 + .json = "permanent_db",
221 + .value = VARLIB_DIR,
222 + },
223 + [BIB_DIR_PLUGINS] = {
224 + .category = BIC_DIRECTORIES,
225 + .type = BIT_STRING,
226 + .analytics = NULL,
227 + .print = "Plugins",
228 + .json = "plugins",
229 + .value = PLUGINS_DIR,
230 + },
231 + [BIB_DIR_WEB] = {
232 + .category = BIC_DIRECTORIES,
233 + .type = BIT_STRING,
234 + .analytics = NULL,
235 + .print = "Static Web Files",
236 + .json = "web",
237 + .value = WEB_DIR,
238 + },
239 + [BIB_DIR_LOG] = {
240 + .category = BIC_DIRECTORIES,
241 + .type = BIT_STRING,
242 + .analytics = NULL,
243 + .print = "Log Files",
244 + .json = "logs",
245 + .value = LOG_DIR,
246 + },
247 + [BIB_DIR_LOCK] = {
248 + .category = BIC_DIRECTORIES,
249 + .type = BIT_STRING,
250 + .analytics = NULL,
251 + .print = "Lock Files",
252 + .json = "locks",
253 + .value = VARLIB_DIR "/lock",
254 + },
255 + [BIB_DIR_HOME] = {
256 + .category = BIC_DIRECTORIES,
257 + .type = BIT_STRING,
258 + .analytics = NULL,
259 + .print = "Home",
260 + .json = "home",
261 + .value = VARLIB_DIR,
262 + },
263 + [BIB_OS_KERNEL_NAME] = {
264 + .category = BIC_OPERATING_SYSTEM,
265 + .type = BIT_STRING,
266 + .analytics = NULL,
267 + .print = "Kernel",
268 + .json = "kernel",
269 + .value = "unknown",
270 + },
271 + [BIB_OS_KERNEL_VERSION] = {
272 + .category = BIC_OPERATING_SYSTEM,
273 + .type = BIT_STRING,
274 + .analytics = NULL,
275 + .print = "Kernel Version",
276 + .json = "kernel_version",
277 + .value = "unknown",
278 + },
279 + [BIB_OS_NAME] = {
280 + .category = BIC_OPERATING_SYSTEM,
281 + .type = BIT_STRING,
282 + .analytics = NULL,
283 + .print = "Operating System",
284 + .json = "os",
285 + .value = "unknown",
286 + },
287 + [BIB_OS_ID] = {
288 + .category = BIC_OPERATING_SYSTEM,
289 + .type = BIT_STRING,
290 + .analytics = NULL,
291 + .print = "Operating System ID",
292 + .json = "id",
293 + .value = "unknown",
294 + },
295 + [BIB_OS_ID_LIKE] = {
296 + .category = BIC_OPERATING_SYSTEM,
297 + .type = BIT_STRING,
298 + .analytics = NULL,
299 + .print = "Operating System ID Like",
300 + .json = "id_like",
301 + .value = "unknown",
302 + },
303 + [BIB_OS_VERSION] = {
304 + .category = BIC_OPERATING_SYSTEM,
305 + .type = BIT_STRING,
306 + .analytics = NULL,
307 + .print = "Operating System Version",
308 + .json = "version",
309 + .value = "unknown",
310 + },
311 + [BIB_OS_VERSION_ID] = {
312 + .category = BIC_OPERATING_SYSTEM,
313 + .type = BIT_STRING,
314 + .analytics = NULL,
315 + .print = "Operating System Version ID",
316 + .json = "version_id",
317 + .value = "unknown",
318 + },
319 + [BIB_OS_DETECTION] = {
320 + .category = BIC_OPERATING_SYSTEM,
321 + .type = BIT_STRING,
322 + .analytics = NULL,
323 + .print = "Detection",
324 + .json = "detection",
325 + .value = "unknown",
326 + },
327 + [BIB_HW_CPU_CORES] = {
328 + .category = BIC_HARDWARE,
329 + .type = BIT_STRING,
330 + .analytics = NULL,
331 + .print = "CPU Cores",
332 + .json = "cpu_cores",
333 + .value = "unknown",
334 + },
335 + [BIB_HW_CPU_FREQUENCY] = {
336 + .category = BIC_HARDWARE,
337 + .type = BIT_STRING,
338 + .analytics = NULL,
339 + .print = "CPU Frequency",
340 + .json = "cpu_frequency",
341 + .value = "unknown",
342 + },
343 + [BIB_HW_RAM_SIZE] = {
344 + .category = BIC_HARDWARE,
345 + .type = BIT_STRING,
346 + .analytics = NULL,
347 + .print = "CPU Architecture",
348 + .json = "cpu_architecture",
349 + .value = "unknown",
350 + },
351 + [BIB_HW_DISK_SPACE] = {
352 + .category = BIC_HARDWARE,
353 + .type = BIT_STRING,
354 + .analytics = NULL,
355 + .print = "RAM Bytes",
356 + .json = "ram",
357 + .value = "unknown",
358 + },
359 + [BIB_HW_ARCHITECTURE] = {
360 + .category = BIC_HARDWARE,
361 + .type = BIT_STRING,
362 + .analytics = NULL,
363 + .print = "Disk Capacity",
364 + .json = "disk",
365 + .value = "unknown",
366 + },
367 + [BIB_HW_VIRTUALIZATION] = {
368 + .category = BIC_HARDWARE,
369 + .type = BIT_STRING,
370 + .analytics = NULL,
371 + .print = "Virtualization Technology",
372 + .json = "virtualization",
373 + .value = "unknown",
374 + },
375 + [BIB_HW_VIRTUALIZATION_DETECTION] = {
376 + .category = BIC_HARDWARE,
377 + .type = BIT_STRING,
378 + .analytics = NULL,
379 + .print = "Virtualization Detection",
380 + .json = "virtualization_detection",
381 + .value = "unknown",
382 + },
383 + [BIB_CONTAINER_NAME] = {
384 + .category = BIC_CONTAINER,
385 + .type = BIT_STRING,
386 + .analytics = NULL,
387 + .print = "Container",
388 + .json = "container",
389 + .value = "unknown",
390 + },
391 + [BIB_CONTAINER_DETECTION] = {
392 + .category = BIC_CONTAINER,
393 + .type = BIT_STRING,
394 + .analytics = NULL,
395 + .print = "Container Detection",
396 + .json = "container_detection",
397 + .value = "unknown",
398 + },
399 + [BIB_CONTAINER_ORCHESTRATOR] = {
400 + .category = BIC_CONTAINER,
401 + .type = BIT_STRING,
402 + .analytics = NULL,
403 + .print = "Container Orchestrator",
404 + .json = "orchestrator",
405 + .value = "unknown",
406 + },
407 + [BIB_CONTAINER_OS_NAME] = {
408 + .category = BIC_CONTAINER,
409 + .type = BIT_STRING,
410 + .analytics = NULL,
411 + .print = "Container Operating System",
412 + .json = "os",
413 + .value = "unknown",
414 + },
415 + [BIB_CONTAINER_OS_ID] = {
416 + .category = BIC_CONTAINER,
417 + .type = BIT_STRING,
418 + .analytics = NULL,
419 + .print = "Container Operating System ID",
420 + .json = "os_id",
421 + .value = "unknown",
422 + },
423 + [BIB_CONTAINER_OS_ID_LIKE] = {
424 + .category = BIC_CONTAINER,
425 + .type = BIT_STRING,
426 + .analytics = NULL,
427 + .print = "Container Operating System ID Like",
428 + .json = "os_id_like",
429 + .value = "unknown",
430 + },
431 + [BIB_CONTAINER_OS_VERSION] = {
432 + .category = BIC_CONTAINER,
433 + .type = BIT_STRING,
434 + .analytics = NULL,
435 + .print = "Container Operating System Version",
436 + .json = "version",
437 + .value = "unknown",
438 + },
439 + [BIB_CONTAINER_OS_VERSION_ID] = {
440 + .category = BIC_CONTAINER,
441 + .type = BIT_STRING,
442 + .analytics = NULL,
443 + .print = "Container Operating System Version ID",
444 + .json = "version_id",
445 + .value = "unknown",
446 + },
447 + [BIB_CONTAINER_OS_DETECTION] = {
448 + .category = BIC_CONTAINER,
449 + .type = BIT_STRING,
450 + .analytics = NULL,
451 + .print = "Container Operating System Detection",
452 + .json = "detection",
453 + .value = "unknown",
454 + },
455 + [BIB_FEATURE_BUILT_FOR] = {
456 + .category = BIC_FEATURE,
457 + .type = BIT_STRING,
458 + .analytics = NULL,
459 + .print = "Built For",
460 + .json = "built-for",
461 + .value = "unknown",
462 + },
463 + [BIB_FEATURE_CLOUD] = {
464 + .category = BIC_FEATURE,
465 + .type = BIT_BOOLEAN,
466 + .analytics = "Netdata Cloud",
467 + .print = "Netdata Cloud",
468 + .json = "cloud",
469 + .value = NULL,
470 + },
471 + [BIB_FEATURE_HEALTH] = {
472 + .category = BIC_FEATURE,
473 + .type = BIT_BOOLEAN,
474 + .analytics = NULL,
475 + .print = "Health (trigger alerts and send notifications)",
476 + .json = "health",
477 + .value = NULL,
478 + },
479 + [BIB_FEATURE_STREAMING] = {
480 + .category = BIC_FEATURE,
481 + .type = BIT_BOOLEAN,
482 + .analytics = NULL,
483 + .print = "Streaming (stream metrics to parent Netdata servers)",
484 + .json = "streaming",
485 + .value = NULL,
486 + },
487 + [BIB_FEATURE_REPLICATION] = {
488 + .category = BIC_FEATURE,
489 + .type = BIT_BOOLEAN,
490 + .analytics = NULL,
491 + .print = "Replication (fill the gaps of parent Netdata servers)",
492 + .json = "replication",
493 + .value = NULL,
494 + },
495 + [BIB_FEATURE_STREAMING_COMPRESSION] = {
496 + .category = BIC_FEATURE,
497 + .type = BIT_BOOLEAN,
498 + .analytics = "Stream Compression",
499 + .print = "Streaming and Replication Compression",
500 + .json = "stream-compression",
501 + .value = "none",
502 + },
503 + [BIB_FEATURE_CONTEXTS] = {
504 + .category = BIC_FEATURE,
505 + .type = BIT_BOOLEAN,
506 + .analytics = NULL,
507 + .print = "Contexts (index all active and archived metrics)",
508 + .json = "contexts",
509 + .value = NULL,
510 + },
511 + [BIB_FEATURE_TIERING] = {
512 + .category = BIC_FEATURE,
513 + .type = BIT_BOOLEAN,
514 + .analytics = NULL,
515 + .print = "Tiering (multiple dbs with different metrics resolution)",
516 + .json = "tiering",
517 + .value = TOSTRING(RRD_STORAGE_TIERS),
518 + },
519 + [BIB_FEATURE_ML] = {
520 + .category = BIC_FEATURE,
521 + .type = BIT_BOOLEAN,
522 + .analytics = "Machine Learning",
523 + .print = "Machine Learning",
524 + .json = "ml",
525 + .value = NULL,
526 + },
527 + [BIB_DB_DBENGINE] = {
528 + .category = BIC_DATABASE,
529 + .type = BIT_BOOLEAN,
530 + .analytics = "dbengine",
531 + .print = "dbengine",
532 + .json = "dbengine",
533 + .value = NULL,
534 + },
535 + [BIB_DB_ALLOC] = {
536 + .category = BIC_DATABASE,
537 + .type = BIT_BOOLEAN,
538 + .analytics = NULL,
539 + .print = "alloc",
540 + .json = "alloc",
541 + .value = NULL,
542 + },
543 + [BIB_DB_RAM] = {
544 + .category = BIC_DATABASE,
545 + .type = BIT_BOOLEAN,
546 + .analytics = NULL,
547 + .print = "ram",
548 + .json = "ram",
549 + .value = NULL,
550 + },
551 + [BIB_DB_MAP] = {
552 + .category = BIC_DATABASE,
553 + .type = BIT_BOOLEAN,
554 + .analytics = NULL,
555 + .print = "map",
556 + .json = "map",
557 + .value = NULL,
558 + },
559 + [BIB_DB_SAVE] = {
560 + .category = BIC_DATABASE,
561 + .type = BIT_BOOLEAN,
562 + .analytics = NULL,
563 + .print = "save",
564 + .json = "save",
565 + .value = NULL,
566 + },
567 + [BIB_DB_NONE] = {
568 + .category = BIC_DATABASE,
569 + .type = BIT_BOOLEAN,
570 + .analytics = NULL,
571 + .print = "none",
572 + .json = "none",
573 + .value = NULL,
574 + },
575 + [BIB_CONNECTIVITY_ACLK] = {
576 + .category = BIC_CONNECTIVITY,
577 + .type = BIT_BOOLEAN,
578 + .analytics = NULL,
579 + .print = "ACLK (Agent-Cloud Link: MQTT over WebSockets over TLS)",
580 + .json = "aclk",
581 + .value = NULL,
582 + },
583 + [BIB_CONNECTIVITY_HTTPD_STATIC] = {
584 + .category = BIC_CONNECTIVITY,
585 + .type = BIT_BOOLEAN,
586 + .analytics = NULL,
587 + .print = "static (Netdata internal web server)",
588 + .json = "static",
589 + .value = NULL,
590 + },
591 + [BIB_CONNECTIVITY_HTTPD_H2O] = {
592 + .category = BIC_CONNECTIVITY,
593 + .type = BIT_BOOLEAN,
594 + .analytics = NULL,
595 + .print = "h2o (web server)",
596 + .json = "h2o",
597 + .value = NULL,
598 + },
599 + [BIB_CONNECTIVITY_WEBRTC] = {
600 + .category = BIC_CONNECTIVITY,
601 + .type = BIT_BOOLEAN,
602 + .analytics = NULL,
603 + .print = "WebRTC (experimental)",
604 + .json = "webrtc",
605 + .value = NULL,
606 + },
607 + [BIB_CONNECTIVITY_NATIVE_HTTPS] = {
608 + .category = BIC_CONNECTIVITY,
609 + .type = BIT_BOOLEAN,
610 + .analytics = "Native HTTPS",
611 + .print = "Native HTTPS (TLS Support)",
612 + .json = "native-https",
613 + .value = NULL,
614 + },
615 + [BIB_CONNECTIVITY_TLS_HOST_VERIFY] = {
616 + .category = BIC_CONNECTIVITY,
617 + .type = BIT_BOOLEAN,
618 + .analytics = "TLS Host Verification",
619 + .print = "TLS Host Verification",
620 + .json = "tls-host-verify",
621 + .value = NULL,
622 + },
623 + [BIB_LIB_LZ4] = {
624 + .category = BIC_LIBS,
625 + .type = BIT_BOOLEAN,
626 + .analytics = NULL,
627 + .print = "LZ4 (extremely fast lossless compression algorithm)",
628 + .json = "lz4",
629 + .value = NULL,
630 + },
631 + [BIB_LIB_ZLIB] = {
632 + .category = BIC_LIBS,
633 + .type = BIT_BOOLEAN,
634 + .analytics = "zlib",
635 + .print = "zlib (lossless data-compression library)",
636 + .json = "zlib",
637 + .value = NULL,
638 + },
639 + [BIB_LIB_JUDY] = {
640 + .category = BIC_LIBS,
641 + .type = BIT_BOOLEAN,
642 + .analytics = NULL,
643 + .print = "Judy (high-performance dynamic arrays and hashtables)",
644 + .json = "judy",
645 + .status = true,
646 + .value = "bundled",
647 + },
648 + [BIB_LIB_DLIB] = {
649 + .category = BIC_LIBS,
650 + .type = BIT_BOOLEAN,
651 + .analytics = NULL,
652 + .print = "dlib (robust machine learning toolkit)",
653 + .json = "dlib",
654 + .value = NULL,
655 + },
656 + [BIB_LIB_PROTOBUF] = {
657 + .category = BIC_LIBS,
658 + .type = BIT_BOOLEAN,
659 + .analytics = "protobuf",
660 + .print = "protobuf (platform-neutral data serialization protocol)",
661 + .json = "protobuf",
662 + .value = NULL,
663 + },
664 + [BIB_LIB_OPENSSL] = {
665 + .category = BIC_LIBS,
666 + .type = BIT_BOOLEAN,
667 + .analytics = NULL,
668 + .print = "OpenSSL (cryptography)",
669 + .json = "openssl",
670 + .value = NULL,
671 + },
672 + [BIB_LIB_LIBDATACHANNEL] = {
673 + .category = BIC_LIBS,
674 + .type = BIT_BOOLEAN,
675 + .analytics = NULL,
676 + .print = "libdatachannel (stand-alone WebRTC data channels)",
677 + .json = "libdatachannel",
678 + .value = NULL,
679 + },
680 + [BIB_LIB_JSONC] = {
681 + .category = BIC_LIBS,
682 + .type = BIT_BOOLEAN,
683 + .analytics = "JSON-C",
684 + .print = "JSON-C (lightweight JSON manipulation)",
685 + .json = "jsonc",
686 + .value = NULL,
687 + },
688 + [BIB_LIB_LIBCAP] = {
689 + .category = BIC_LIBS,
690 + .type = BIT_BOOLEAN,
691 + .analytics = "libcap",
692 + .print = "libcap (Linux capabilities system operations)",
693 + .json = "libcap",
694 + .value = NULL,
695 + },
696 + [BIB_LIB_LIBCRYPTO] = {
697 + .category = BIC_LIBS,
698 + .type = BIT_BOOLEAN,
699 + .analytics = "libcrypto",
700 + .print = "libcrypto (cryptographic functions)",
701 + .json = "libcrypto",
702 + .value = NULL,
703 + },
704 + [BIB_LIB_LIBM] = {
705 + .category = BIC_LIBS,
706 + .type = BIT_BOOLEAN,
707 + .analytics = "libm",
708 + .print = "libm (mathematical functions)",
709 + .json = "libm",
710 + .value = NULL,
711 + },
712 + [BIB_LIB_JEMALLOC] = {
713 + .category = BIC_LIBS,
714 + .type = BIT_BOOLEAN,
715 + .analytics = "jemalloc",
716 + .print = "jemalloc",
717 + .json = "jemalloc",
718 + .value = NULL,
719 + },
720 + [BIB_LIB_TCMALLOC] = {
721 + .category = BIC_LIBS,
722 + .type = BIT_BOOLEAN,
723 + .analytics = "tcmalloc",
724 + .print = "TCMalloc",
725 + .json = "tcmalloc",
726 + .value = NULL,
727 + },
728 + [BIB_PLUGIN_APPS] = {
729 + .category = BIC_PLUGINS,
730 + .type = BIT_BOOLEAN,
731 + .analytics = "apps",
732 + .print = "apps (monitor processes)",
733 + .json = "apps",
734 + .value = NULL,
735 + },
736 + [BIB_PLUGIN_LINUX_CGROUPS] = {
737 + .category = BIC_PLUGINS,
738 + .type = BIT_BOOLEAN,
739 + .analytics = NULL,
740 + .print = "cgroups (monitor containers and VMs)",
741 + .json = "cgroups",
742 + .value = NULL,
743 + },
744 + [BIB_PLUGIN_LINUX_CGROUP_NETWORK] = {
745 + .category = BIC_PLUGINS,
746 + .type = BIT_BOOLEAN,
747 + .analytics = "cgroup Network Tracking",
748 + .print = "cgroup-network (associate interfaces to CGROUPS)",
749 + .json = "cgroup-network",
750 + .value = NULL,
751 + },
752 + [BIB_PLUGIN_LINUX_PROC] = {
753 + .category = BIC_PLUGINS,
754 + .type = BIT_BOOLEAN,
755 + .analytics = NULL,
756 + .print = "proc (monitor Linux systems)",
757 + .json = "proc",
758 + .value = NULL,
759 + },
760 + [BIB_PLUGIN_LINUX_TC] = {
761 + .category = BIC_PLUGINS,
762 + .type = BIT_BOOLEAN,
763 + .analytics = NULL,
764 + .print = "tc (monitor Linux network QoS)",
765 + .json = "tc",
766 + .value = NULL,
767 + },
768 + [BIB_PLUGIN_LINUX_DISKSPACE] = {
769 + .category = BIC_PLUGINS,
770 + .type = BIT_BOOLEAN,
771 + .analytics = NULL,
772 + .print = "diskspace (monitor Linux mount points)",
773 + .json = "diskspace",
774 + .value = NULL,
775 + },
776 + [BIB_PLUGIN_FREEBSD] = {
777 + .category = BIC_PLUGINS,
778 + .type = BIT_BOOLEAN,
779 + .analytics = NULL,
780 + .print = "freebsd (monitor FreeBSD systems)",
781 + .json = "freebsd",
782 + .value = NULL,
783 + },
784 + [BIB_PLUGIN_MACOS] = {
785 + .category = BIC_PLUGINS,
786 + .type = BIT_BOOLEAN,
787 + .analytics = NULL,
788 + .print = "macos (monitor MacOS systems)",
789 + .json = "macos",
790 + .value = NULL,
791 + },
792 + [BIB_PLUGIN_STATSD] = {
793 + .category = BIC_PLUGINS,
794 + .type = BIT_BOOLEAN,
795 + .analytics = NULL,
796 + .print = "statsd (collect custom application metrics)",
797 + .json = "statsd",
798 + .value = NULL,
799 + },
800 + [BIB_PLUGIN_TIMEX] = {
801 + .category = BIC_PLUGINS,
802 + .type = BIT_BOOLEAN,
803 + .analytics = NULL,
804 + .print = "timex (check system clock synchronization)",
805 + .json = "timex",
806 + .value = NULL,
807 + },
808 + [BIB_PLUGIN_IDLEJITTER] = {
809 + .category = BIC_PLUGINS,
810 + .type = BIT_BOOLEAN,
811 + .analytics = NULL,
812 + .print = "idlejitter (check system latency and jitter)",
813 + .json = "idlejitter",
814 + .value = NULL,
815 + },
816 + [BIB_PLUGIN_BASH] = {
817 + .category = BIC_PLUGINS,
818 + .type = BIT_BOOLEAN,
819 + .analytics = NULL,
820 + .print = "bash (support shell data collection jobs - charts.d)",
821 + .json = "charts.d",
822 + .value = NULL,
823 + },
824 + [BIB_PLUGIN_DEBUGFS] = {
825 + .category = BIC_PLUGINS,
826 + .type = BIT_BOOLEAN,
827 + .analytics = "debugfs",
828 + .print = "debugfs (kernel debugging metrics)",
829 + .json = "debugfs",
830 + .value = NULL,
831 + },
832 + [BIB_PLUGIN_CUPS] = {
833 + .category = BIC_PLUGINS,
834 + .type = BIT_BOOLEAN,
835 + .analytics = "CUPS",
836 + .print = "cups (monitor printers and print jobs)",
837 + .json = "cups",
838 + .value = NULL,
839 + },
840 + [BIB_PLUGIN_EBPF] = {
841 + .category = BIC_PLUGINS,
842 + .type = BIT_BOOLEAN,
843 + .analytics = "EBPF",
844 + .print = "ebpf (monitor system calls)",
845 + .json = "ebpf",
846 + .value = NULL,
847 + },
848 + [BIB_PLUGIN_FREEIPMI] = {
849 + .category = BIC_PLUGINS,
850 + .type = BIT_BOOLEAN,
851 + .analytics = "IPMI",
852 + .print = "freeipmi (monitor enterprise server H/W)",
853 + .json = "freeipmi",
854 + .value = NULL,
855 + },
856 + [BIB_PLUGIN_NFACCT] = {
857 + .category = BIC_PLUGINS,
858 + .type = BIT_BOOLEAN,
859 + .analytics = "NFACCT",
860 + .print = "nfacct (gather netfilter accounting)",
861 + .json = "nfacct",
862 + .value = NULL,
863 + },
864 + [BIB_PLUGIN_PERF] = {
865 + .category = BIC_PLUGINS,
866 + .type = BIT_BOOLEAN,
867 + .analytics = "perf",
868 + .print = "perf (collect kernel performance events)",
869 + .json = "perf",
870 + .value = NULL,
871 + },
872 + [BIB_PLUGIN_SLABINFO] = {
873 + .category = BIC_PLUGINS,
874 + .type = BIT_BOOLEAN,
875 + .analytics = "slabinfo",
876 + .print = "slabinfo (monitor kernel object caching)",
877 + .json = "slabinfo",
878 + .value = NULL,
879 + },
880 + [BIB_PLUGIN_XEN] = {
881 + .category = BIC_PLUGINS,
882 + .type = BIT_BOOLEAN,
883 + .analytics = "Xen",
884 + .print = "Xen",
885 + .json = "xen",
886 + .value = NULL,
887 + },
888 + [BIB_PLUGIN_XEN_VBD_ERROR] = {
889 + .category = BIC_PLUGINS,
890 + .type = BIT_BOOLEAN,
891 + .analytics = "Xen VBD Error Tracking",
892 + .print = "Xen VBD Error Tracking",
893 + .json = "xen-vbd-error",
894 + .value = NULL,
895 + },
896 + [BIB_EXPORT_MONGOC] = {
897 + .category = BIC_EXPORTERS,
898 + .type = BIT_BOOLEAN,
899 + .analytics = "MongoDB",
900 + .print = "MongoDB",
901 + .json = "mongodb",
902 + .value = NULL,
903 + },
904 + [BIB_EXPORT_GRAPHITE] = {
905 + .category = BIC_EXPORTERS,
906 + .type = BIT_BOOLEAN,
907 + .analytics = NULL,
908 + .print = "Graphite",
909 + .json = "graphite",
910 + .value = NULL,
911 + },
912 + [BIB_EXPORT_GRAPHITE_HTTP] = {
913 + .category = BIC_EXPORTERS,
914 + .type = BIT_BOOLEAN,
915 + .analytics = NULL,
916 + .print = "Graphite HTTP / HTTPS",
917 + .json = "graphite:http",
918 + .value = NULL,
919 + },
920 + [BIB_EXPORT_JSON] = {
921 + .category = BIC_EXPORTERS,
922 + .type = BIT_BOOLEAN,
923 + .analytics = NULL,
924 + .print = "JSON",
925 + .json = "json",
926 + .value = NULL,
927 + },
928 + [BIB_EXPORT_JSON_HTTP] = {
929 + .category = BIC_EXPORTERS,
930 + .type = BIT_BOOLEAN,
931 + .analytics = NULL,
932 + .print = "JSON HTTP / HTTPS",
933 + .json = "json:http",
934 + .value = NULL,
935 + },
936 + [BIB_EXPORT_OPENTSDB] = {
937 + .category = BIC_EXPORTERS,
938 + .type = BIT_BOOLEAN,
939 + .analytics = NULL,
940 + .print = "OpenTSDB",
941 + .json = "opentsdb",
942 + .value = NULL,
943 + },
944 + [BIB_EXPORT_OPENTSDB_HTTP] = {
945 + .category = BIC_EXPORTERS,
946 + .type = BIT_BOOLEAN,
947 + .analytics = NULL,
948 + .print = "OpenTSDB HTTP / HTTPS",
949 + .json = "opentsdb:http",
950 + .value = NULL,
951 + },
952 + [BIB_EXPORT_ALLMETRICS] = {
953 + .category = BIC_EXPORTERS,
954 + .analytics = NULL,
955 + .type = BIT_BOOLEAN,
956 + .print = "All Metrics API",
957 + .json = "allmetrics",
958 + .value = NULL,
959 + },
960 + [BIB_EXPORT_SHELL] = {
961 + .category = BIC_EXPORTERS,
962 + .type = BIT_BOOLEAN,
963 + .analytics = NULL,
964 + .print = "Shell (use metrics in shell scripts)",
965 + .json = "shell",
966 + .value = NULL,
967 + },
968 + [BIB_EXPORT_PROMETHEUS_EXPORTER] = {
969 + .category = BIC_EXPORTERS,
970 + .type = BIT_BOOLEAN,
971 + .analytics = NULL,
972 + .print = "Prometheus (OpenMetrics) Exporter",
973 + .json = "openmetrics",
974 + .value = NULL,
975 + },
976 + [BIB_EXPORT_PROMETHEUS_REMOTE_WRITE] = {
977 + .category = BIC_EXPORTERS,
978 + .type = BIT_BOOLEAN,
979 + .analytics = "Prometheus Remote Write",
980 + .print = "Prometheus Remote Write",
981 + .json = "prom-remote-write",
982 + .value = NULL,
983 + },
984 + [BIB_EXPORT_AWS_KINESIS] = {
985 + .category = BIC_EXPORTERS,
986 + .type = BIT_BOOLEAN,
987 + .analytics = "AWS Kinesis",
988 + .print = "AWS Kinesis",
989 + .json = "kinesis",
990 + .value = NULL,
991 + },
992 + [BIB_EXPORT_GCP_PUBSUB] = {
993 + .category = BIC_EXPORTERS,
994 + .type = BIT_BOOLEAN,
995 + .analytics = "GCP PubSub",
996 + .print = "GCP PubSub",
997 + .json = "pubsub",
998 + .value = NULL,
999 + },
1000 + [BIB_DEVEL_TRACE_ALLOCATIONS] = {
1001 + .category = BIC_DEBUG_DEVEL,
1002 + .type = BIT_BOOLEAN,
1003 + .analytics = "DebugTraceAlloc",
1004 + .print = "Trace All Netdata Allocations (with charts)",
1005 + .json = "trace-allocations",
1006 + .value = NULL,
1007 + },
1008 + [BIB_DEVELOPER_MODE] = {
1009 + .category = BIC_DEBUG_DEVEL,
1010 + .type = BIT_BOOLEAN,
1011 + .analytics = NULL,
1012 + .print = "Developer Mode (more runtime checks, slower)",
1013 + .json = "dev-mode",
1014 + .value = NULL,
1015 + },
1016 +
1017 + // leave this last
1018 + [BIB_TERMINATOR] = {
1019 + .category = 0,
1020 + .type = 0,
1021 + .analytics = NULL,
1022 + .print = NULL,
1023 + .json = NULL,
1024 + .value = NULL,
1025 + },
1026 +};
1027 +
1028 +static void build_info_set_value(BUILD_INFO_SLOT slot, const char *value) {
1029 + BUILD_INFO[slot].value = value;
1030 +}
1031 +
1032 +static void build_info_set_value_strdupz(BUILD_INFO_SLOT slot, const char *value) {
1033 + if(!value) value = "";
1034 + build_info_set_value(slot, strdupz(value));
1035 +}
1036 +
1037 +static void build_info_set_status(BUILD_INFO_SLOT slot, bool status) {
1038 + BUILD_INFO[slot].status = status;
1039 +}
1040 +
1041 +__attribute__((constructor)) void initialize_build_info(void) {
1042 + build_info_set_value(BIB_PACKAGING_NETDATA_VERSION, program_version);
1043 + build_info_set_value(BIB_PACKAGING_CONFIGURE_OPTIONS, CONFIGURE_COMMAND);
1044 +
1045 +#ifdef COMPILED_FOR_LINUX
1046 + build_info_set_status(BIB_FEATURE_BUILT_FOR, true);
1047 + build_info_set_value(BIB_FEATURE_BUILT_FOR, "Linux");
1048 + build_info_set_status(BIB_PLUGIN_LINUX_CGROUPS, true);
1049 + build_info_set_status(BIB_PLUGIN_LINUX_PROC, true);
1050 + build_info_set_status(BIB_PLUGIN_LINUX_DISKSPACE, true);
1051 + build_info_set_status(BIB_PLUGIN_LINUX_TC, true);
1052 +#endif
1053 +#ifdef COMPILED_FOR_FREEBSD
1054 + build_info_set_status(BIB_FEATURE_BUILT_FOR, true);
1055 + build_info_set_value(BIB_FEATURE_BUILT_FOR, "FreeBSD");
1056 + build_info_set_status(BIB_PLUGIN_FREEBSD, true);
1057 +#endif
1058 +#ifdef COMPILED_FOR_MACOS
1059 + build_info_set_status(BIB_FEATURE_BUILT_FOR, true);
1060 + build_info_set_value(BIB_FEATURE_BUILT_FOR, "MacOS");
1061 + build_info_set_status(BIB_PLUGIN_MACOS, true);
1062 +#endif
1063
1064 #ifdef ENABLE_ACLK
11 -#define FEAT_CLOUD 1
12 -#define FEAT_CLOUD_MSG ""
1065 + build_info_set_status(BIB_FEATURE_CLOUD, true);
1066 + build_info_set_status(BIB_CONNECTIVITY_ACLK, true);
1067 #else
1068 + build_info_set_status(BIB_FEATURE_CLOUD, false);
1069 #ifdef DISABLE_CLOUD
15 -#define FEAT_CLOUD 0
16 -#define FEAT_CLOUD_MSG "(by user request)"
1070 + build_info_set_value(BIB_FEATURE_CLOUD, "disabled");
1071 #else
18 -#define FEAT_CLOUD 0
19 -#define FEAT_CLOUD_MSG ""
1072 + build_info_set_value(BIB_FEATURE_CLOUD, "unavailable");
1073 #endif
1074 #endif
1075
23 -#ifdef ENABLE_HTTPD
24 -#define FEAT_HTTPD 1
25 -#else
26 -#define FEAT_HTTPD 0
27 -#endif
1076 + build_info_set_status(BIB_FEATURE_HEALTH, true);
1077 + build_info_set_status(BIB_FEATURE_STREAMING, true);
1078 + build_info_set_status(BIB_FEATURE_REPLICATION, true);
1079
29 -#ifdef ENABLE_DBENGINE
30 -#define FEAT_DBENGINE 1
31 -#else
32 -#define FEAT_DBENGINE 0
1080 +#ifdef ENABLE_RRDPUSH_COMPRESSION
1081 + build_info_set_status(BIB_FEATURE_STREAMING_COMPRESSION, true);
1082 +#ifdef ENABLE_LZ4
1083 + build_info_set_value(BIB_FEATURE_STREAMING_COMPRESSION, "lz4");
1084 +#endif
1085 #endif
1086
35 -#if defined(HAVE_X509_VERIFY_PARAM_set1_host) && HAVE_X509_VERIFY_PARAM_set1_host == 1
36 -#define FEAT_TLS_HOST_VERIFY 1
37 -#else
38 -#define FEAT_TLS_HOST_VERIFY 0
1087 + build_info_set_status(BIB_FEATURE_CONTEXTS, true);
1088 + build_info_set_status(BIB_FEATURE_TIERING, true);
1089 +
1090 +#ifdef ENABLE_ML
1091 + build_info_set_status(BIB_FEATURE_ML, true);
1092 #endif
1093
1094 +#ifdef ENABLE_DBENGINE
1095 + build_info_set_status(BIB_DB_DBENGINE, true);
1096 +#endif
1097 + build_info_set_status(BIB_DB_ALLOC, true);
1098 + build_info_set_status(BIB_DB_RAM, true);
1099 + build_info_set_status(BIB_DB_MAP, true);
1100 + build_info_set_status(BIB_DB_SAVE, true);
1101 + build_info_set_status(BIB_DB_NONE, true);
1102 +
1103 + build_info_set_status(BIB_CONNECTIVITY_HTTPD_STATIC, true);
1104 +#ifdef ENABLE_H2O
1105 + build_info_set_status(BIB_CONNECTIVITY_HTTPD_H2O, true);
1106 +#endif
1107 +#ifdef ENABLE_WEBRTC
1108 + build_info_set_status(BIB_CONNECTIVITY_WEBRTC, true);
1109 +#endif
1110 #ifdef ENABLE_HTTPS
42 -#define FEAT_NATIVE_HTTPS 1
43 -#else
44 -#define FEAT_NATIVE_HTTPS 0
1111 + build_info_set_status(BIB_CONNECTIVITY_NATIVE_HTTPS, true);
1112 #endif
46 -
47 -#ifdef ENABLE_ML
48 -#define FEAT_ML 1
49 -#else
50 -#define FEAT_ML 0
1113 +#if defined(HAVE_X509_VERIFY_PARAM_set1_host) && HAVE_X509_VERIFY_PARAM_set1_host == 1
1114 + build_info_set_status(BIB_CONNECTIVITY_TLS_HOST_VERIFY, true);
1115 #endif
1116
53 -#ifdef ENABLE_COMPRESSION
54 -#define FEAT_STREAM_COMPRESSION 1
55 -#else
56 -#define FEAT_STREAM_COMPRESSION 0
57 -#endif //ENABLE_COMPRESSION
1117 +#ifdef ENABLE_LZ4
1118 + build_info_set_status(BIB_LIB_LZ4, true);
1119 +#endif
1120
1121 + build_info_set_status(BIB_LIB_ZLIB, true);
1122
60 -// Optional libraries
1123 +#ifdef HAVE_DLIB
1124 + build_info_set_status(BIB_LIB_DLIB, true);
1125 + build_info_set_value(BIB_LIB_DLIB, "bundled");
1126 +#endif
1127
1128 #ifdef HAVE_PROTOBUF
63 -#define FEAT_PROTOBUF 1
1129 + build_info_set_status(BIB_LIB_PROTOBUF, true);
1130 #ifdef BUNDLED_PROTOBUF
65 -#define FEAT_PROTOBUF_BUNDLED " (bundled)"
1131 + build_info_set_value(BIB_LIB_PROTOBUF, "bundled");
1132 #else
67 -#define FEAT_PROTOBUF_BUNDLED " (system)"
1133 + build_info_set_value(BIB_LIB_PROTOBUF, "system");
1134 #endif
69 -#else
70 -#define FEAT_PROTOBUF 0
71 -#define FEAT_PROTOBUF_BUNDLED ""
1135 #endif
1136
74 -#ifdef ENABLE_JSONC
75 -#define FEAT_JSONC 1
76 -#else
77 -#define FEAT_JSONC 0
1137 +#ifdef HAVE_LIBDATACHANNEL
1138 + build_info_set_status(BIB_LIB_LIBDATACHANNEL, true);
1139 #endif
79 -
80 -#ifdef ENABLE_JEMALLOC
81 -#define FEAT_JEMALLOC 1
82 -#else
83 -#define FEAT_JEMALLOC 0
1140 +#ifdef ENABLE_OPENSSL
1141 + build_info_set_status(BIB_LIB_OPENSSL, true);
1142 #endif
85 -
86 -#ifdef ENABLE_TCMALLOC
87 -#define FEAT_TCMALLOC 1
88 -#else
89 -#define FEAT_TCMALLOC 0
1143 +#ifdef ENABLE_JSONC
1144 + build_info_set_status(BIB_LIB_JSONC, true);
1145 #endif
91 -
1146 #ifdef HAVE_CAPABILITY
93 -#define FEAT_LIBCAP 1
94 -#else
95 -#define FEAT_LIBCAP 0
96 -#endif
97 -
98 -#ifdef STORAGE_WITH_MATH
99 -#define FEAT_LIBM 1
100 -#else
101 -#define FEAT_LIBM 0
1147 + build_info_set_status(BIB_LIB_LIBCAP, true);
1148 #endif
103 -
1149 #ifdef HAVE_CRYPTO
105 -#define FEAT_CRYPTO 1
106 -#else
107 -#define FEAT_CRYPTO 0
1150 + build_info_set_status(BIB_LIB_LIBCRYPTO, true);
1151 #endif
109 -
110 -// Optional plugins
111 -
112 -#ifdef ENABLE_APPS_PLUGIN
113 -#define FEAT_APPS_PLUGIN 1
114 -#else
115 -#define FEAT_APPS_PLUGIN 0
1152 +#ifdef STORAGE_WITH_MATH
1153 + build_info_set_status(BIB_LIB_LIBM, true);
1154 #endif
117 -
118 -#ifdef ENABLE_DEBUGFS_PLUGIN
119 -#define FEAT_DEBUGFS_PLUGIN 1
120 -#else
121 -#define FEAT_DEBUGFS_PLUGIN 0
1155 +#ifdef ENABLE_JEMALLOC
1156 + build_info_set_status(BIB_LIB_JEMALLOC, true);
1157 #endif
123 -
124 -#ifdef HAVE_FREEIPMI
125 -#define FEAT_IPMI 1
126 -#else
127 -#define FEAT_IPMI 0
1158 +#ifdef ENABLE_TCMALLOC
1159 + build_info_set_status(BIB_LIB_TCMALLOC, true);
1160 #endif
1161
130 -#ifdef HAVE_CUPS
131 -#define FEAT_CUPS 1
132 -#else
133 -#define FEAT_CUPS 0
1162 +#ifdef ENABLE_APPS_PLUGIN
1163 + build_info_set_status(BIB_PLUGIN_APPS, true);
1164 #endif
135 -
136 -#ifdef HAVE_NFACCT
137 -#define FEAT_NFACCT 1
138 -#else
139 -#define FEAT_NFACCT 0
1165 +#ifdef HAVE_SETNS
1166 + build_info_set_status(BIB_PLUGIN_LINUX_CGROUP_NETWORK, true);
1167 #endif
1168
142 -#ifdef HAVE_LIBXENSTAT
143 -#define FEAT_XEN 1
144 -#else
145 -#define FEAT_XEN 0
146 -#endif
1169 + build_info_set_status(BIB_PLUGIN_STATSD, true);
1170 + build_info_set_status(BIB_PLUGIN_TIMEX, true);
1171 + build_info_set_status(BIB_PLUGIN_IDLEJITTER, true);
1172 + build_info_set_status(BIB_PLUGIN_BASH, true);
1173
148 -#ifdef HAVE_XENSTAT_VBD_ERROR
149 -#define FEAT_XEN_VBD_ERROR 1
150 -#else
151 -#define FEAT_XEN_VBD_ERROR 0
1174 +#ifdef ENABLE_DEBUGFS_PLUGIN
1175 + build_info_set_status(BIB_PLUGIN_DEBUGFS, true);
1176 +#endif
1177 +#ifdef HAVE_CUPS
1178 + build_info_set_status(BIB_PLUGIN_CUPS, true);
1179 #endif
153 -
1180 #ifdef HAVE_LIBBPF
155 -#define FEAT_EBPF 1
156 -#else
157 -#define FEAT_EBPF 0
1181 + build_info_set_status(BIB_PLUGIN_EBPF, true);
1182 #endif
159 -
160 -#ifdef HAVE_SETNS
161 -#define FEAT_CGROUP_NET 1
162 -#else
163 -#define FEAT_CGROUP_NET 0
1183 +#ifdef HAVE_FREEIPMI
1184 + build_info_set_status(BIB_PLUGIN_FREEIPMI, true);
1185 +#endif
1186 +#ifdef HAVE_NFACCT
1187 + build_info_set_status(BIB_PLUGIN_NFACCT, true);
1188 #endif
165 -
1189 #ifdef ENABLE_PERF_PLUGIN
167 -#define FEAT_PERF 1
168 -#else
169 -#define FEAT_PERF 0
1190 + build_info_set_status(BIB_PLUGIN_PERF, true);
1191 #endif
171 -
1192 #ifdef ENABLE_SLABINFO
173 -#define FEAT_SLABINFO 1
174 -#else
175 -#define FEAT_SLABINFO 0
1193 + build_info_set_status(BIB_PLUGIN_SLABINFO, true);
1194 +#endif
1195 +#ifdef HAVE_LIBXENSTAT
1196 + build_info_set_status(BIB_PLUGIN_XEN, true);
1197 +#endif
1198 +#ifdef HAVE_XENSTAT_VBD_ERROR
1199 + build_info_set_status(BIB_PLUGIN_XEN_VBD_ERROR, true);
1200 #endif
1201
178 -// Optional Exporters
1202 + build_info_set_status(BIB_EXPORT_PROMETHEUS_EXPORTER, true);
1203 + build_info_set_status(BIB_EXPORT_GRAPHITE, true);
1204 + build_info_set_status(BIB_EXPORT_GRAPHITE_HTTP, true);
1205 + build_info_set_status(BIB_EXPORT_JSON, true);
1206 + build_info_set_status(BIB_EXPORT_JSON_HTTP, true);
1207 + build_info_set_status(BIB_EXPORT_OPENTSDB, true);
1208 + build_info_set_status(BIB_EXPORT_OPENTSDB_HTTP, true);
1209 + build_info_set_status(BIB_EXPORT_ALLMETRICS, true);
1210 + build_info_set_status(BIB_EXPORT_SHELL, true);
1211
1212 #ifdef HAVE_KINESIS
181 -#define FEAT_KINESIS 1
182 -#else
183 -#define FEAT_KINESIS 0
1213 + build_info_set_status(BIB_EXPORT_AWS_KINESIS, true);
1214 #endif
185 -
1215 #ifdef ENABLE_EXPORTING_PUBSUB
187 -#define FEAT_PUBSUB 1
188 -#else
189 -#define FEAT_PUBSUB 0
1216 + build_info_set_status(BIB_EXPORT_GCP_PUBSUB, true);
1217 #endif
191 -
1218 #ifdef HAVE_MONGOC
193 -#define FEAT_MONGO 1
194 -#else
195 -#define FEAT_MONGO 0
1219 + build_info_set_status(BIB_EXPORT_MONGOC, true);
1220 #endif
197 -
1221 #ifdef ENABLE_PROMETHEUS_REMOTE_WRITE
199 -#define FEAT_REMOTE_WRITE 1
200 -#else
201 -#define FEAT_REMOTE_WRITE 0
1222 + build_info_set_status(BIB_EXPORT_PROMETHEUS_REMOTE_WRITE, true);
1223 #endif
1224
204 -#define FEAT_YES_NO(x) ((x) ? "YES" : "NO")
205 -
1225 #ifdef NETDATA_TRACE_ALLOCATIONS
207 -#define FEAT_TRACE_ALLOC 1
208 -#else
209 -#define FEAT_TRACE_ALLOC 0
1226 + build_info_set_status(BIB_DEVEL_TRACE_ALLOCATIONS, true);
1227 +#endif
1228 +
1229 +#if defined(NETDATA_DEV_MODE) || defined(NETDATA_INTERNAL_CHECKS)
1230 + build_info_set_status(BIB_DEVELOPER_MODE, true);
1231 #endif
1232 +}
1233 +
1234 +// ----------------------------------------------------------------------------
1235 +// system info
1236 +
1237 +int get_system_info(struct rrdhost_system_info *system_info, bool log);
1238 +static void populate_system_info(void) {
1239 + static bool populated = false;
1240 + static SPINLOCK spinlock = NETDATA_SPINLOCK_INITIALIZER;
1241 +
1242 + if(populated)
1243 + return;
1244 +
1245 + spinlock_lock(&spinlock);
1246 +
1247 + if(populated) {
1248 + spinlock_unlock(&spinlock);
1249 + return;
1250 + }
1251 +
1252 + struct rrdhost_system_info *system_info;
1253 + bool free_system_info = false;
1254 +
1255 + if(localhost && localhost->system_info) {
1256 + system_info = localhost->system_info;
1257 + }
1258 + else {
1259 + system_info = callocz(1, sizeof(struct rrdhost_system_info));
1260 + get_system_info(system_info, false);
1261 + free_system_info = true;
1262 + }
1263 +
1264 + build_info_set_value_strdupz(BIB_OS_KERNEL_NAME, system_info->kernel_name);
1265 + build_info_set_value_strdupz(BIB_OS_KERNEL_VERSION, system_info->kernel_version);
1266 + build_info_set_value_strdupz(BIB_OS_NAME, system_info->host_os_name);
1267 + build_info_set_value_strdupz(BIB_OS_ID, system_info->host_os_id);
1268 + build_info_set_value_strdupz(BIB_OS_ID_LIKE, system_info->host_os_id_like);
1269 + build_info_set_value_strdupz(BIB_OS_VERSION, system_info->host_os_version);
1270 + build_info_set_value_strdupz(BIB_OS_VERSION_ID, system_info->container_os_version_id);
1271 + build_info_set_value_strdupz(BIB_OS_DETECTION, system_info->host_os_detection);
1272 + build_info_set_value_strdupz(BIB_HW_CPU_CORES, system_info->host_cores);
1273 + build_info_set_value_strdupz(BIB_HW_CPU_FREQUENCY, system_info->host_cpu_freq);
1274 + build_info_set_value_strdupz(BIB_HW_RAM_SIZE, system_info->host_ram_total);
1275 + build_info_set_value_strdupz(BIB_HW_DISK_SPACE, system_info->host_disk_space);
1276 + build_info_set_value_strdupz(BIB_HW_ARCHITECTURE, system_info->architecture);
1277 + build_info_set_value_strdupz(BIB_HW_VIRTUALIZATION, system_info->virtualization);
1278 + build_info_set_value_strdupz(BIB_HW_VIRTUALIZATION_DETECTION, system_info->virt_detection);
1279 + build_info_set_value_strdupz(BIB_CONTAINER_NAME, system_info->container);
1280 + build_info_set_value_strdupz(BIB_CONTAINER_DETECTION, system_info->container_detection);
1281 +
1282 + if(system_info->is_k8s_node && !strcmp(system_info->is_k8s_node, "true"))
1283 + build_info_set_value_strdupz(BIB_CONTAINER_ORCHESTRATOR, "kubernetes");
1284 + else
1285 + build_info_set_value_strdupz(BIB_CONTAINER_ORCHESTRATOR, "none");
1286 +
1287 + build_info_set_value_strdupz(BIB_CONTAINER_OS_NAME, system_info->container_os_name);
1288 + build_info_set_value_strdupz(BIB_CONTAINER_OS_ID, system_info->container_os_id);
1289 + build_info_set_value_strdupz(BIB_CONTAINER_OS_ID_LIKE, system_info->container_os_id_like);
1290 + build_info_set_value_strdupz(BIB_CONTAINER_OS_VERSION, system_info->container_os_version);
1291 + build_info_set_value_strdupz(BIB_CONTAINER_OS_VERSION_ID, system_info->container_os_version_id);
1292 + build_info_set_value_strdupz(BIB_CONTAINER_OS_DETECTION, system_info->container_os_detection);
1293 +
1294 + if(free_system_info)
1295 + rrdhost_system_info_free(system_info);
1296 +
1297 + populated = true;
1298 + spinlock_unlock(&spinlock);
1299 +}
1300 +
1301 +// ----------------------------------------------------------------------------
1302 +// packaging info
1303
1304 char *get_value_from_key(char *buffer, char *key) {
1305 char *s = NULL, *t = NULL;
@@ -247,235 +1339,160 @@ void get_install_type(char **install_type, char **prebuilt_arch, char **prebuilt
1339 freez(install_type_filename);
1340 }
1341
250 -void print_build_info(void) {
251 - char *install_type = NULL;
252 - char *prebuilt_arch = NULL;
253 - char *prebuilt_distro = NULL;
254 - get_install_type(&install_type, &prebuilt_arch, &prebuilt_distro);
1342 +static struct {
1343 + SPINLOCK spinlock;
1344 + bool populated;
1345 + char *install_type;
1346 + char *prebuilt_arch;
1347 + char *prebuilt_distro;
1348 +} BUILD_PACKAGING_INFO = { 0 };
1349 +
1350 +static void populate_packaging_info() {
1351 + if(!BUILD_PACKAGING_INFO.populated) {
1352 + spinlock_lock(&BUILD_PACKAGING_INFO.spinlock);
1353 + if(!BUILD_PACKAGING_INFO.populated) {
1354 + BUILD_PACKAGING_INFO.populated = true;
1355
256 - printf("Configure options: %s\n", CONFIGURE_COMMAND);
1356 + get_install_type(&BUILD_PACKAGING_INFO.install_type, &BUILD_PACKAGING_INFO.prebuilt_arch, &BUILD_PACKAGING_INFO.prebuilt_distro);
1357
258 - if (install_type == NULL) {
259 - printf("Install type: unknown\n");
260 - } else {
261 - printf("Install type: %s\n", install_type);
1358 + if(!BUILD_PACKAGING_INFO.install_type)
1359 + BUILD_PACKAGING_INFO.install_type = "unknown";
1360 +
1361 + if(!BUILD_PACKAGING_INFO.prebuilt_arch)
1362 + BUILD_PACKAGING_INFO.prebuilt_arch = "unknown";
1363 +
1364 + if(!BUILD_PACKAGING_INFO.prebuilt_distro)
1365 + BUILD_PACKAGING_INFO.prebuilt_distro = "unknown";
1366 +
1367 + build_info_set_value(BIB_PACKAGING_INSTALL_TYPE, strdupz(BUILD_PACKAGING_INFO.install_type));
1368 + build_info_set_value(BIB_PACKAGING_ARCHITECTURE, strdupz(BUILD_PACKAGING_INFO.prebuilt_arch));
1369 + build_info_set_value(BIB_PACKAGING_DISTRO, strdupz(BUILD_PACKAGING_INFO.prebuilt_distro));
1370 + }
1371 + spinlock_unlock(&BUILD_PACKAGING_INFO.spinlock);
1372 }
1373 +}
1374
264 - if (prebuilt_arch != NULL) {
265 - printf(" Binary architecture: %s\n", prebuilt_arch);
1375 +// ----------------------------------------------------------------------------
1376 +
1377 +static void populate_directories(void) {
1378 + build_info_set_value(BIB_DIR_USER_CONFIG, netdata_configured_user_config_dir);
1379 + build_info_set_value(BIB_DIR_STOCK_CONFIG, netdata_configured_stock_config_dir);
1380 + build_info_set_value(BIB_DIR_CACHE, netdata_configured_cache_dir);
1381 + build_info_set_value(BIB_DIR_LIB, netdata_configured_varlib_dir);
1382 + build_info_set_value(BIB_DIR_PLUGINS, netdata_configured_primary_plugins_dir);
1383 + build_info_set_value(BIB_DIR_WEB, netdata_configured_web_dir);
1384 + build_info_set_value(BIB_DIR_LOG, netdata_configured_log_dir);
1385 + build_info_set_value(BIB_DIR_LOCK, netdata_configured_lock_dir);
1386 + build_info_set_value(BIB_DIR_HOME, netdata_configured_home_dir);
1387 +}
1388 +
1389 +// ----------------------------------------------------------------------------
1390 +
1391 +static void print_build_info_category_to_json(BUFFER *b, BUILD_INFO_CATEGORY category, const char *key) {
1392 + buffer_json_member_add_object(b, key);
1393 + for(size_t i = 0; i < BIB_TERMINATOR ;i++) {
1394 + if(BUILD_INFO[i].category == category && BUILD_INFO[i].json) {
1395 + if(BUILD_INFO[i].value)
1396 + buffer_json_member_add_string(b, BUILD_INFO[i].json, BUILD_INFO[i].value);
1397 + else
1398 + buffer_json_member_add_boolean(b, BUILD_INFO[i].json, BUILD_INFO[i].status);
1399 + }
1400 }
1401 + buffer_json_object_close(b); // key
1402 +}
1403
268 - if (prebuilt_distro != NULL) {
269 - printf(" Packaging distro: %s\n", prebuilt_distro);
1404 +static void print_build_info_category_to_console(BUILD_INFO_CATEGORY category, const char *title) {
1405 + printf("%s:\n", title);
1406 + for(size_t i = 0; i < BIB_TERMINATOR ;i++) {
1407 + if(BUILD_INFO[i].category == category && BUILD_INFO[i].print) {
1408 + const char *v = BUILD_INFO[i].status ? "YES" : "NO";
1409 + const char *k = BUILD_INFO[i].print;
1410 + const char *d = BUILD_INFO[i].value;
1411 +
1412 + int padding_length = 60 - strlen(k) - 1;
1413 + if (padding_length < 0) padding_length = 0;
1414 +
1415 + char padding[padding_length + 1];
1416 + memset(padding, '_', padding_length);
1417 + padding[padding_length] = '\0';
1418 +
1419 + if(BUILD_INFO[i].type == BIT_STRING)
1420 + printf(" %s %s : %s\n", k, padding, d?d:"unknown");
1421 + else
1422 + printf(" %s %s : %s%s%s%s\n", k, padding, v,
1423 + d?" (":"", d?d:"", d?")":"");
1424 + }
1425 }
1426 +}
1427
272 - freez(install_type);
273 - freez(prebuilt_arch);
274 - freez(prebuilt_distro);
275 -
276 - printf("Features:\n");
277 - printf(" dbengine: %s\n", FEAT_YES_NO(FEAT_DBENGINE));
278 - printf(" Native HTTPS: %s\n", FEAT_YES_NO(FEAT_NATIVE_HTTPS));
279 - printf(" Netdata Cloud: %s %s\n", FEAT_YES_NO(FEAT_CLOUD), FEAT_CLOUD_MSG);
280 - printf(" ACLK: %s\n", FEAT_YES_NO(FEAT_CLOUD));
281 - printf(" TLS Host Verification: %s\n", FEAT_YES_NO(FEAT_TLS_HOST_VERIFY));
282 - printf(" Machine Learning: %s\n", FEAT_YES_NO(FEAT_ML));
283 - printf(" Stream Compression: %s\n", FEAT_YES_NO(FEAT_STREAM_COMPRESSION));
284 - printf(" HTTPD (h2o): %s\n", FEAT_YES_NO(FEAT_HTTPD));
285 -
286 - printf("Libraries:\n");
287 - printf(" protobuf: %s%s\n", FEAT_YES_NO(FEAT_PROTOBUF), FEAT_PROTOBUF_BUNDLED);
288 - printf(" jemalloc: %s\n", FEAT_YES_NO(FEAT_JEMALLOC));
289 - printf(" JSON-C: %s\n", FEAT_YES_NO(FEAT_JSONC));
290 - printf(" libcap: %s\n", FEAT_YES_NO(FEAT_LIBCAP));
291 - printf(" libcrypto: %s\n", FEAT_YES_NO(FEAT_CRYPTO));
292 - printf(" libm: %s\n", FEAT_YES_NO(FEAT_LIBM));
293 - printf(" tcalloc: %s\n", FEAT_YES_NO(FEAT_TCMALLOC));
294 - printf(" zlib: %s\n", FEAT_YES_NO(1));
295 -
296 - printf("Plugins:\n");
297 - printf(" apps: %s\n", FEAT_YES_NO(FEAT_APPS_PLUGIN));
298 - printf(" cgroup Network Tracking: %s\n", FEAT_YES_NO(FEAT_CGROUP_NET));
299 - printf(" CUPS: %s\n", FEAT_YES_NO(FEAT_CUPS));
300 - printf(" debugfs: %s\n", FEAT_YES_NO(FEAT_DEBUGFS_PLUGIN));
301 - printf(" EBPF: %s\n", FEAT_YES_NO(FEAT_EBPF));
302 - printf(" IPMI: %s\n", FEAT_YES_NO(FEAT_IPMI));
303 - printf(" NFACCT: %s\n", FEAT_YES_NO(FEAT_NFACCT));
304 - printf(" perf: %s\n", FEAT_YES_NO(FEAT_PERF));
305 - printf(" slabinfo: %s\n", FEAT_YES_NO(FEAT_SLABINFO));
306 - printf(" Xen: %s\n", FEAT_YES_NO(FEAT_XEN));
307 - printf(" Xen VBD Error Tracking: %s\n", FEAT_YES_NO(FEAT_XEN_VBD_ERROR));
308 -
309 - printf("Exporters:\n");
310 - printf(" AWS Kinesis: %s\n", FEAT_YES_NO(FEAT_KINESIS));
311 - printf(" GCP PubSub: %s\n", FEAT_YES_NO(FEAT_PUBSUB));
312 - printf(" MongoDB: %s\n", FEAT_YES_NO(FEAT_MONGO));
313 - printf(" Prometheus Remote Write: %s\n", FEAT_YES_NO(FEAT_REMOTE_WRITE));
314 -
315 - printf("Debug/Developer Features:\n");
316 - printf(" Trace Allocations: %s\n", FEAT_YES_NO(FEAT_TRACE_ALLOC));
1428 +void print_build_info(void) {
1429 + populate_packaging_info();
1430 + populate_system_info();
1431 + populate_directories();
1432 +
1433 + print_build_info_category_to_console(BIC_PACKAGING, "Packaging");
1434 + print_build_info_category_to_console(BIC_DIRECTORIES, "Default Directories");
1435 + print_build_info_category_to_console(BIC_OPERATING_SYSTEM, "Operating System");
1436 + print_build_info_category_to_console(BIC_HARDWARE, "Hardware");
1437 + print_build_info_category_to_console(BIC_CONTAINER, "Container");
1438 + print_build_info_category_to_console(BIC_FEATURE, "Features");
1439 + print_build_info_category_to_console(BIC_DATABASE, "Database Engines");
1440 + print_build_info_category_to_console(BIC_CONNECTIVITY, "Connectivity Capabilities");
1441 + print_build_info_category_to_console(BIC_LIBS, "Libraries");
1442 + print_build_info_category_to_console(BIC_PLUGINS, "Plugins");
1443 + print_build_info_category_to_console(BIC_EXPORTERS, "Exporters");
1444 + print_build_info_category_to_console(BIC_DEBUG_DEVEL, "Debug/Developer Features");
1445 };
1446
319 -#define FEAT_JSON_BOOL(x) ((x) ? "true" : "false")
320 -// This intentionally does not use JSON-C so it works even if JSON-C is not present
321 -// This is used for anonymous statistics reporting, so it intentionally
322 -// does not include the configure options, which would be very easy to use
323 -// for tracking custom builds (and complicate outputting valid JSON).
1447 +void build_info_to_json_object(BUFFER *b) {
1448 + populate_packaging_info();
1449 + populate_system_info();
1450 + populate_directories();
1451 +
1452 + print_build_info_category_to_json(b, BIC_PACKAGING, "package");
1453 + print_build_info_category_to_json(b, BIC_DIRECTORIES, "directories");
1454 + print_build_info_category_to_json(b, BIC_OPERATING_SYSTEM, "os");
1455 + print_build_info_category_to_json(b, BIC_HARDWARE, "hw");
1456 + print_build_info_category_to_json(b, BIC_CONTAINER, "container");
1457 + print_build_info_category_to_json(b, BIC_FEATURE, "features");
1458 + print_build_info_category_to_json(b, BIC_DATABASE, "databases");
1459 + print_build_info_category_to_json(b, BIC_CONNECTIVITY, "connectivity");
1460 + print_build_info_category_to_json(b, BIC_LIBS, "libs");
1461 + print_build_info_category_to_json(b, BIC_PLUGINS, "plugins");
1462 + print_build_info_category_to_json(b, BIC_EXPORTERS, "exporters");
1463 + print_build_info_category_to_json(b, BIC_DEBUG_DEVEL, "debug-n-devel");
1464 +}
1465 +
1466 void print_build_info_json(void) {
325 - printf("{\n");
326 - printf(" \"features\": {\n");
327 - printf(" \"dbengine\": %s,\n", FEAT_JSON_BOOL(FEAT_DBENGINE));
328 - printf(" \"native-https\": %s,\n", FEAT_JSON_BOOL(FEAT_NATIVE_HTTPS));
329 - printf(" \"cloud\": %s,\n", FEAT_JSON_BOOL(FEAT_CLOUD));
330 -#ifdef DISABLE_CLOUD
331 - printf(" \"cloud-disabled\": true,\n");
332 -#else
333 - printf(" \"cloud-disabled\": false,\n");
334 -#endif
335 - printf(" \"aclk\": %s,\n", FEAT_JSON_BOOL(FEAT_CLOUD));
336 -
337 - printf(" \"tls-host-verify\": %s,\n", FEAT_JSON_BOOL(FEAT_TLS_HOST_VERIFY));
338 - printf(" \"machine-learning\": %s\n", FEAT_JSON_BOOL(FEAT_ML));
339 - printf(" \"stream-compression\": %s\n", FEAT_JSON_BOOL(FEAT_STREAM_COMPRESSION));
340 - printf(" \"httpd-h2o\": %s\n", FEAT_JSON_BOOL(FEAT_HTTPD));
341 - printf(" },\n");
342 -
343 - printf(" \"libs\": {\n");
344 - printf(" \"protobuf\": %s,\n", FEAT_JSON_BOOL(FEAT_PROTOBUF));
345 - printf(" \"protobuf-source\": \"%s\",\n", FEAT_PROTOBUF_BUNDLED);
346 - printf(" \"jemalloc\": %s,\n", FEAT_JSON_BOOL(FEAT_JEMALLOC));
347 - printf(" \"jsonc\": %s,\n", FEAT_JSON_BOOL(FEAT_JSONC));
348 - printf(" \"libcap\": %s,\n", FEAT_JSON_BOOL(FEAT_LIBCAP));
349 - printf(" \"libcrypto\": %s,\n", FEAT_JSON_BOOL(FEAT_CRYPTO));
350 - printf(" \"libm\": %s,\n", FEAT_JSON_BOOL(FEAT_LIBM));
351 - printf(" \"tcmalloc\": %s,\n", FEAT_JSON_BOOL(FEAT_TCMALLOC));
352 - printf(" \"zlib\": %s\n", FEAT_JSON_BOOL(1));
353 - printf(" },\n");
354 -
355 - printf(" \"plugins\": {\n");
356 - printf(" \"apps\": %s,\n", FEAT_JSON_BOOL(FEAT_APPS_PLUGIN));
357 - printf(" \"cgroup-net\": %s,\n", FEAT_JSON_BOOL(FEAT_CGROUP_NET));
358 - printf(" \"cups\": %s,\n", FEAT_JSON_BOOL(FEAT_CUPS));
359 - printf(" \"debugfs\": %s,\n", FEAT_JSON_BOOL(FEAT_DEBUGFS_PLUGIN));
360 - printf(" \"ebpf\": %s,\n", FEAT_JSON_BOOL(FEAT_EBPF));
361 - printf(" \"ipmi\": %s,\n", FEAT_JSON_BOOL(FEAT_IPMI));
362 - printf(" \"nfacct\": %s,\n", FEAT_JSON_BOOL(FEAT_NFACCT));
363 - printf(" \"perf\": %s,\n", FEAT_JSON_BOOL(FEAT_PERF));
364 - printf(" \"slabinfo\": %s,\n", FEAT_JSON_BOOL(FEAT_SLABINFO));
365 - printf(" \"xen\": %s,\n", FEAT_JSON_BOOL(FEAT_XEN));
366 - printf(" \"xen-vbd-error\": %s\n", FEAT_JSON_BOOL(FEAT_XEN_VBD_ERROR));
367 - printf(" },\n");
368 -
369 - printf(" \"exporters\": {\n");
370 - printf(" \"kinesis\": %s,\n", FEAT_JSON_BOOL(FEAT_KINESIS));
371 - printf(" \"pubsub\": %s,\n", FEAT_JSON_BOOL(FEAT_PUBSUB));
372 - printf(" \"mongodb\": %s,\n", FEAT_JSON_BOOL(FEAT_MONGO));
373 - printf(" \"prom-remote-write\": %s\n", FEAT_JSON_BOOL(FEAT_REMOTE_WRITE));
374 - printf(" }\n");
375 - printf(" \"debug-n-devel\": {\n");
376 - printf(" \"trace-allocations\": %s\n }\n",FEAT_JSON_BOOL(FEAT_TRACE_ALLOC));
377 - printf("}\n");
378 -};
1467 + populate_packaging_info();
1468 + populate_system_info();
1469 + populate_directories();
1470
380 -#define add_to_bi(buffer, str) \
381 - { if(first) { \
382 - buffer_strcat (b, str); \
383 - first = 0; \
384 - } else \
385 - buffer_strcat (b, "|" str); }
1471 + BUFFER *b = buffer_create(0, NULL);
1472 + buffer_json_initialize(b, "\"", "\"", 0, true, false);
1473
387 -void analytics_build_info(BUFFER *b) {
388 - int first = 1;
389 -#ifdef ENABLE_DBENGINE
390 - add_to_bi(b, "dbengine");
391 -#endif
392 -#ifdef ENABLE_HTTPS
393 - add_to_bi(b, "Native HTTPS");
394 -#endif
395 -#ifdef ENABLE_ACLK
396 - add_to_bi(b, "Netdata Cloud");
397 -#endif
398 -#if (FEAT_TLS_HOST_VERIFY!=0)
399 - add_to_bi(b, "TLS Host Verification");
400 -#endif
401 -#ifdef ENABLE_ML
402 - add_to_bi(b, "Machine Learning");
403 -#endif
404 -#ifdef ENABLE_COMPRESSION
405 - add_to_bi(b, "Stream Compression");
406 -#endif
1474 + build_info_to_json_object(b);
1475
408 -#ifdef HAVE_PROTOBUF
409 - add_to_bi(b, "protobuf");
410 -#endif
411 -#ifdef ENABLE_JEMALLOC
412 - add_to_bi(b, "jemalloc");
413 -#endif
414 -#ifdef ENABLE_JSONC
415 - add_to_bi(b, "JSON-C");
416 -#endif
417 -#ifdef HAVE_CAPABILITY
418 - add_to_bi(b, "libcap");
419 -#endif
420 -#ifdef HAVE_CRYPTO
421 - add_to_bi(b, "libcrypto");
422 -#endif
423 -#ifdef STORAGE_WITH_MATH
424 - add_to_bi(b, "libm");
425 -#endif
1476 + buffer_json_finalize(b);
1477 + printf("%s\n", buffer_tostring(b));
1478 + buffer_free(b);
1479 +};
1480
427 -#ifdef ENABLE_TCMALLOC
428 - add_to_bi(b, "tcalloc");
429 -#endif
430 - add_to_bi(b, "zlib");
1481 +void analytics_build_info(BUFFER *b) {
1482 + populate_packaging_info();
1483 + populate_system_info();
1484 + populate_directories();
1485
432 -#ifdef ENABLE_APPS_PLUGIN
433 - add_to_bi(b, "apps");
434 -#endif
435 -#ifdef ENABLE_DEBUGFS_PLUGIN
436 - add_to_bi(b, "debugfs");
437 -#endif
438 -#ifdef HAVE_SETNS
439 - add_to_bi(b, "cgroup Network Tracking");
440 -#endif
441 -#ifdef HAVE_CUPS
442 - add_to_bi(b, "CUPS");
443 -#endif
444 -#ifdef HAVE_LIBBPF
445 - add_to_bi(b, "EBPF");
446 -#endif
447 -#ifdef HAVE_FREEIPMI
448 - add_to_bi(b, "IPMI");
449 -#endif
450 -#ifdef HAVE_NFACCT
451 - add_to_bi(b, "NFACCT");
452 -#endif
453 -#ifdef ENABLE_PERF_PLUGIN
454 - add_to_bi(b, "perf");
455 -#endif
456 -#ifdef ENABLE_SLABINFO
457 - add_to_bi(b, "slabinfo");
458 -#endif
459 -#ifdef HAVE_LIBXENSTAT
460 - add_to_bi(b, "Xen");
461 -#endif
462 -#ifdef HAVE_XENSTAT_VBD_ERROR
463 - add_to_bi(b, "Xen VBD Error Tracking");
464 -#endif
1486 + size_t added = 0;
1487 + for(size_t i = 0; i < BIB_TERMINATOR ;i++) {
1488 + if(BUILD_INFO[i].analytics && BUILD_INFO[i].status) {
1489
466 -#ifdef HAVE_KINESIS
467 - add_to_bi(b, "AWS Kinesis");
468 -#endif
469 -#ifdef ENABLE_EXPORTING_PUBSUB
470 - add_to_bi(b, "GCP PubSub");
471 -#endif
472 -#ifdef HAVE_MONGOC
473 - add_to_bi(b, "MongoDB");
474 -#endif
475 -#ifdef ENABLE_PROMETHEUS_REMOTE_WRITE
476 - add_to_bi(b, "Prometheus Remote Write");
477 -#endif
478 -#ifdef NETDATA_TRACE_ALLOCATIONS
479 - add_to_bi(b, "DebugTraceAlloc");
480 -#endif
1490 + if(added)
1491 + buffer_strcat(b, "|");
1492 +
1493 + buffer_strcat (b, BUILD_INFO[i].analytics);
1494 + added++;
1495 + }
1496 + }
1497 }
1498 +
daemon/buildinfo.h
+2
@@ -11,4 +11,6 @@ char *get_value_from_key(char *buffer, char *key);
11
12 void get_install_type(char **install_type, char **prebuilt_arch, char **prebuilt_dist);
13
14 +void build_info_to_json_object(BUFFER *b);
15 +
16 #endif // NETDATA_BUILDINFO_H
daemon/commands.c
+1 -5
@@ -209,12 +209,8 @@ static cmd_status_t cmd_reload_claiming_state_execute(char *args, char **message
209 *message = strdupz("This agent cannot be claimed, it was built without support for Cloud");
210 return CMD_STATUS_FAILURE;
211 #endif
212 - error_log_limit_unlimited();
212 netdata_log_info("COMMAND: Reloading Agent Claiming configuration.");
214 - load_claiming_state();
215 - registry_update_cloud_base_url();
216 - rrdpush_send_claimed_id(localhost);
217 - error_log_limit_reset();
213 + claim_reload_all();
214 return CMD_STATUS_SUCCESS;
215 }
216
daemon/common.c
+51 -7
@@ -6,11 +6,11 @@ char *netdata_configured_hostname = NULL;
6 char *netdata_configured_user_config_dir = CONFIG_DIR;
7 char *netdata_configured_stock_config_dir = LIBCONFIG_DIR;
8 char *netdata_configured_log_dir = LOG_DIR;
9 -char *netdata_configured_primary_plugins_dir = NULL;
9 +char *netdata_configured_primary_plugins_dir = PLUGINS_DIR;
10 char *netdata_configured_web_dir = WEB_DIR;
11 char *netdata_configured_cache_dir = CACHE_DIR;
12 char *netdata_configured_varlib_dir = VARLIB_DIR;
13 -char *netdata_configured_lock_dir = NULL;
13 +char *netdata_configured_lock_dir = VARLIB_DIR "/lock";
14 char *netdata_configured_home_dir = VARLIB_DIR;
15 char *netdata_configured_host_prefix = NULL;
16 char *netdata_configured_timezone = NULL;
@@ -20,9 +20,9 @@ int32_t netdata_configured_utc_offset = 0;
20 bool netdata_ready = false;
21
22 #if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
23 -bool netdata_cloud_enabled = false;
23 +int netdata_cloud_enabled = CONFIG_BOOLEAN_NO;
24 #else
25 -bool netdata_cloud_enabled = true;
25 +int netdata_cloud_enabled = CONFIG_BOOLEAN_AUTO;
26 #endif
27
28 long get_netdata_cpus(void) {
@@ -67,6 +67,12 @@ long get_netdata_cpus(void) {
67 const char *cloud_status_to_string(CLOUD_STATUS status) {
68 switch(status) {
69 default:
70 + case CLOUD_STATUS_UNAVAILABLE:
71 + return "unavailable";
72 +
73 + case CLOUD_STATUS_AVAILABLE:
74 + return "available";
75 +
76 case CLOUD_STATUS_DISABLED:
77 return "disabled";
78
@@ -89,12 +95,21 @@ CLOUD_STATUS cloud_status(void) {
95 if(aclk_connected)
96 return CLOUD_STATUS_ONLINE;
97
92 - if(netdata_cloud_enabled)
93 - return CLOUD_STATUS_OFFLINE;
98 + if(netdata_cloud_enabled == CONFIG_BOOLEAN_YES) {
99 + char *agent_id = get_agent_claimid();
100 + bool claimed = agent_id != NULL;
101 + freez(agent_id);
102 +
103 + if(claimed)
104 + return CLOUD_STATUS_OFFLINE;
105 + }
106 +
107 + if(netdata_cloud_enabled != CONFIG_BOOLEAN_NO)
108 + return CLOUD_STATUS_AVAILABLE;
109
110 return CLOUD_STATUS_DISABLED;
111 #else
97 - return CLOUD_STATUS_DISABLED;
112 + return CLOUD_STATUS_UNAVAILABLE;
113 #endif
114 }
115
@@ -145,3 +160,32 @@ const char *cloud_base_url() {
160 return NULL;
161 #endif
162 }
163 +
164 +CLOUD_STATUS buffer_json_cloud_status(BUFFER *wb, time_t now_s) {
165 + CLOUD_STATUS status = cloud_status();
166 +
167 + buffer_json_member_add_object(wb, "cloud");
168 + {
169 + size_t id = cloud_connection_id();
170 + time_t last_change = cloud_last_change();
171 + time_t next_connect = cloud_next_connection_attempt();
172 + buffer_json_member_add_uint64(wb, "id", id);
173 + buffer_json_member_add_string(wb, "status", cloud_status_to_string(status));
174 + buffer_json_member_add_time_t(wb, "since", last_change);
175 + buffer_json_member_add_time_t(wb, "age", now_s - last_change);
176 +
177 + if (status != CLOUD_STATUS_ONLINE)
178 + buffer_json_member_add_string(wb, "reason", cloud_offline_reason());
179 +
180 + if (status == CLOUD_STATUS_OFFLINE && next_connect > now_s) {
181 + buffer_json_member_add_time_t(wb, "next_check", next_connect);
182 + buffer_json_member_add_time_t(wb, "next_in", next_connect - now_s);
183 + }
184 +
185 + if (status != CLOUD_STATUS_DISABLED && cloud_base_url())
186 + buffer_json_member_add_string(wb, "url", cloud_base_url());
187 + }
188 + buffer_json_object_close(wb); // cloud
189 +
190 + return status;
191 +}
daemon/common.h
+10 -7
@@ -42,8 +42,8 @@
42 #include "web/server/web_server.h"
43
44 // the new h2o based netdata webserver
45 -#ifdef ENABLE_HTTPD
46 -#include "httpd/http_server.h"
45 +#ifdef ENABLE_H2O
46 +#include "web/server/h2o/http_server.h"
47 #endif
48
49 // streaming metrics between netdata servers
@@ -111,17 +111,19 @@ extern int netdata_zero_metrics_enabled;
111 extern int netdata_anonymous_statistics_enabled;
112
113 extern bool netdata_ready;
114 -extern bool netdata_cloud_enabled;
114 +extern int netdata_cloud_enabled;
115
116 extern time_t netdata_start_time;
117
118 long get_netdata_cpus(void);
119
120 typedef enum __attribute__((packed)) {
121 - CLOUD_STATUS_DISABLED = 0,
122 - CLOUD_STATUS_BANNED,
123 - CLOUD_STATUS_OFFLINE,
124 - CLOUD_STATUS_ONLINE,
121 + CLOUD_STATUS_UNAVAILABLE = 0, // cloud and aclk functionality is not available on this agent
122 + CLOUD_STATUS_AVAILABLE, // cloud and aclk functionality is available, but the agent is not claimed
123 + CLOUD_STATUS_DISABLED, // cloud and aclk functionality is available, but it is disabled
124 + CLOUD_STATUS_BANNED, // the agent has been banned from cloud
125 + CLOUD_STATUS_OFFLINE, // the agent tries to connect to cloud, but cannot do it
126 + CLOUD_STATUS_ONLINE, // the agent is connected to cloud
127 } CLOUD_STATUS;
128
129 const char *cloud_status_to_string(CLOUD_STATUS status);
@@ -131,5 +133,6 @@ time_t cloud_next_connection_attempt(void);
133 size_t cloud_connection_id(void);
134 const char *cloud_offline_reason(void);
135 const char *cloud_base_url(void);
136 +CLOUD_STATUS buffer_json_cloud_status(BUFFER *wb, time_t now_s);
137
138 #endif /* NETDATA_COMMON_H */
daemon/main.c
+33 -51
@@ -1206,7 +1206,22 @@ static void get_netdata_configured_variables() {
1206
1207 }
1208
1209 -int load_netdata_conf(char *filename, char overwrite_used) {
1209 +static void post_conf_load(char **user)
1210 +{
1211 + // --------------------------------------------------------------------
1212 + // get the user we should run
1213 +
1214 + // IMPORTANT: this is required before web_files_uid()
1215 + if(getuid() == 0) {
1216 + *user = config_get(CONFIG_SECTION_GLOBAL, "run as user", NETDATA_USER);
1217 + }
1218 + else {
1219 + struct passwd *passwd = getpwuid(getuid());
1220 + *user = config_get(CONFIG_SECTION_GLOBAL, "run as user", (passwd && passwd->pw_name)?passwd->pw_name:"");
1221 + }
1222 +}
1223 +
1224 +static bool load_netdata_conf(char *filename, char overwrite_used, char **user) {
1225 errno = 0;
1226
1227 int ret = 0;
@@ -1233,6 +1248,7 @@ int load_netdata_conf(char *filename, char overwrite_used) {
1248 freez(filename);
1249 }
1250
1251 + post_conf_load(user);
1252 return ret;
1253 }
1254
@@ -1242,20 +1258,18 @@ static inline void coverity_remove_taint(char *s)
1258 (void)s;
1259 }
1260
1245 -int get_system_info(struct rrdhost_system_info *system_info) {
1261 +int get_system_info(struct rrdhost_system_info *system_info, bool log) {
1262 char *script;
1263 script = mallocz(sizeof(char) * (strlen(netdata_configured_primary_plugins_dir) + strlen("system-info.sh") + 2));
1264 sprintf(script, "%s/%s", netdata_configured_primary_plugins_dir, "system-info.sh");
1265 if (unlikely(access(script, R_OK) != 0)) {
1250 - netdata_log_info("System info script %s not found.",script);
1266 + error("System info script %s not found.",script);
1267 freez(script);
1268 return 1;
1269 }
1270
1271 pid_t command_pid;
1272
1257 - netdata_log_info("Executing %s", script);
1258 -
1273 FILE *fp_child_input;
1274 FILE *fp_child_output = netdata_popen(script, &command_pid, &fp_child_input);
1275 if(fp_child_output) {
@@ -1275,10 +1289,12 @@ int get_system_info(struct rrdhost_system_info *system_info) {
1289 coverity_remove_taint(value);
1290
1291 if(unlikely(rrdhost_set_system_info_variable(system_info, line, value))) {
1278 - netdata_log_info("Unexpected environment variable %s=%s", line, value);
1292 + error("Unexpected environment variable %s=%s", line, value);
1293 }
1294 else {
1281 - netdata_log_info("%s=%s", line, value);
1295 + if(log)
1296 + netdata_log_info("%s=%s", line, value);
1297 +
1298 setenv(line, value, 1);
1299 }
1300 }
@@ -1298,30 +1314,6 @@ void set_silencers_filename() {
1314 /* Any config setting that can be accessed without a default value i.e. configget(...,...,NULL) *MUST*
1315 be set in this procedure to be called in all the relevant code paths.
1316 */
1301 -void post_conf_load(char **user)
1302 -{
1303 - // --------------------------------------------------------------------
1304 - // get the user we should run
1305 -
1306 - // IMPORTANT: this is required before web_files_uid()
1307 - if(getuid() == 0) {
1308 - *user = config_get(CONFIG_SECTION_GLOBAL, "run as user", NETDATA_USER);
1309 - }
1310 - else {
1311 - struct passwd *passwd = getpwuid(getuid());
1312 - *user = config_get(CONFIG_SECTION_GLOBAL, "run as user", (passwd && passwd->pw_name)?passwd->pw_name:"");
1313 - }
1314 -
1315 - // --------------------------------------------------------------------
1316 - // Check if the cloud is enabled
1317 -#if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
1318 - netdata_cloud_enabled = false;
1319 -#else
1320 - netdata_cloud_enabled = appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", 1);
1321 -#endif
1322 - // This must be set before any point in the code that accesses it. Do not move it from this function.
1323 - appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", DEFAULT_CLOUD_BASE_URL);
1324 -}
1317
1318 #define delta_startup_time(msg) \
1319 { \
@@ -1393,13 +1385,12 @@ int main(int argc, char **argv) {
1385 while( (opt = getopt(argc, argv, optstring)) != -1 ) {
1386 switch(opt) {
1387 case 'c':
1396 - if(load_netdata_conf(optarg, 1) != 1) {
1388 + if(!load_netdata_conf(optarg, 1, &user)) {
1389 error("Cannot load configuration file %s.", optarg);
1390 return 1;
1391 }
1392 else {
1393 debug(D_OPTIONS, "Configuration loaded from %s.", optarg);
1402 - post_conf_load(&user);
1394 load_cloud_conf(1);
1395 config_loaded = 1;
1396 }
@@ -1473,7 +1464,7 @@ int main(int argc, char **argv) {
1464 return 1;
1465 if (buffer_unittest())
1466 return 1;
1476 - if (unit_test_bitmap256())
1467 + if (unit_test_bitmaps())
1468 return 1;
1469 // No call to load the config file on this code-path
1470 post_conf_load(&user);
@@ -1736,8 +1727,7 @@ int main(int argc, char **argv) {
1727
1728 if(!config_loaded) {
1729 fprintf(stderr, "warning: no configuration file has been loaded. Use -c CONFIG_FILE, before -W get. Using default config.\n");
1739 - load_netdata_conf(NULL, 0);
1740 - post_conf_load(&user);
1730 + load_netdata_conf(NULL, 0, &user);
1731 }
1732
1733 get_netdata_configured_variables();
@@ -1764,8 +1754,7 @@ int main(int argc, char **argv) {
1754
1755 if(!config_loaded) {
1756 fprintf(stderr, "warning: no configuration file has been loaded. Use -c CONFIG_FILE, before -W get. Using default config.\n");
1767 - load_netdata_conf(NULL, 0);
1768 - post_conf_load(&user);
1757 + load_netdata_conf(NULL, 0, &user);
1758 load_cloud_conf(1);
1759 }
1760
@@ -1785,7 +1774,6 @@ int main(int argc, char **argv) {
1774 claiming_pending_arguments = optarg + strlen(claim_string);
1775 }
1776 else if(strcmp(optarg, "buildinfo") == 0) {
1788 - printf("Version: %s %s\n", program_name, program_version);
1777 print_build_info();
1778 return 0;
1779 }
@@ -1821,16 +1809,10 @@ int main(int argc, char **argv) {
1809
1810
1811 if(!config_loaded) {
1824 - load_netdata_conf(NULL, 0);
1825 - post_conf_load(&user);
1812 + load_netdata_conf(NULL, 0, &user);
1813 load_cloud_conf(0);
1814 }
1815
1829 - char *nd_disable_cloud = getenv("NETDATA_DISABLE_CLOUD");
1830 - if (nd_disable_cloud && !strncmp(nd_disable_cloud, "1", 1)) {
1831 - appconfig_set(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", "false");
1832 - }
1833 -
1816 // ------------------------------------------------------------------------
1817 // initialize netdata
1818 {
@@ -1988,10 +1970,10 @@ int main(int argc, char **argv) {
1970 if(web_server_mode != WEB_SERVER_MODE_NONE)
1971 api_listen_sockets_setup();
1972
1991 -#ifdef ENABLE_HTTPD
1992 - delta_startup_time("initialize httpd server");
1973 +#ifdef ENABLE_H2O
1974 + delta_startup_time("initialize h2o server");
1975 for (int i = 0; static_threads[i].name; i++) {
1994 - if (static_threads[i].start_routine == httpd_main)
1976 + if (static_threads[i].start_routine == h2o_main)
1977 static_threads[i].enabled = httpd_is_enabled();
1978 }
1979 #endif
@@ -2049,7 +2031,7 @@ int main(int argc, char **argv) {
2031 netdata_anonymous_statistics_enabled=-1;
2032 struct rrdhost_system_info *system_info = callocz(1, sizeof(struct rrdhost_system_info));
2033 __atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(struct rrdhost_system_info), __ATOMIC_RELAXED);
2052 - get_system_info(system_info);
2034 + get_system_info(system_info, true);
2035 (void) registry_get_this_machine_guid();
2036 system_info->hops = 0;
2037 get_install_type(&system_info->install_type, &system_info->prebuilt_arch, &system_info->prebuilt_dist);
@@ -2080,7 +2062,7 @@ int main(int argc, char **argv) {
2062 delta_startup_time("collect claiming info");
2063
2064 if (claiming_pending_arguments)
2083 - claim_agent(claiming_pending_arguments);
2065 + claim_agent(claiming_pending_arguments, false, NULL);
2066 load_claiming_state();
2067
2068 // ------------------------------------------------------------------------
daemon/static_threads.c
+3 -3
@@ -143,15 +143,15 @@ const struct netdata_static_thread static_threads_common[] = {
143 .start_routine = socket_listen_main_static_threaded
144 },
145
146 -#ifdef ENABLE_HTTPD
146 +#ifdef ENABLE_H2O
147 {
148 - .name = "httpd",
148 + .name = "h2o",
149 .config_section = NULL,
150 .config_name = NULL,
151 .enabled = 0,
152 .thread = NULL,
153 .init_routine = NULL,
154 - .start_routine = httpd_main
154 + .start_routine = h2o_main
155 },
156 #endif
157
daemon/unit_test.c
+92 -108
@@ -1701,131 +1701,115 @@ error:
1701 return 1;
1702 }
1703
1704 -int unit_test_bitmap256(void) {
1705 - fprintf(stderr, "%s() running...\n", __FUNCTION__ );
1704 +static int bitmapX_test(BITMAPX *ptr, char *expected, const char *msg) {
1705 + int errors = 0;
1706
1707 - BITMAP256 test_bitmap = {0};
1708 -
1709 - bitmap256_set_bit(&test_bitmap, 0, 1);
1710 - bitmap256_set_bit(&test_bitmap, 64, 1);
1711 - bitmap256_set_bit(&test_bitmap, 128, 1);
1712 - bitmap256_set_bit(&test_bitmap, 192, 1);
1713 - if (test_bitmap.data[0] == 1)
1714 - fprintf(stderr, "%s() INDEX 1 is OK\n", __FUNCTION__ );
1715 - if (test_bitmap.data[1] == 1)
1716 - fprintf(stderr, "%s() INDEX 65 is OK\n", __FUNCTION__ );
1717 - if (test_bitmap.data[2] == 1)
1718 - fprintf(stderr, "%s() INDEX 129 is OK\n", __FUNCTION__ );
1719 - if (test_bitmap.data[3] == 1)
1720 - fprintf(stderr, "%s() INDEX 192 is OK\n", __FUNCTION__ );
1721 -
1722 - uint8_t i=0;
1723 - int j = 0;
1724 - do {
1725 - bitmap256_set_bit(&test_bitmap, i++, 1);
1726 - j++;
1727 - } while (j < 256);
1707 + for(uint32_t idx = 0; idx < ptr->bits ; idx++) {
1708 + bool found_set = bitmapX_get_bit(ptr, idx);
1709 + bool expected_set = expected[idx];
1710
1729 - if (test_bitmap.data[0] == 0xffffffffffffffff)
1730 - fprintf(stderr, "%s() INDEX 0 is fully set OK\n", __FUNCTION__);
1731 - else {
1732 - fprintf(stderr, "%s() INDEX 0 is %"PRIu64" expected 0xffffffffffffffff\n", __FUNCTION__, test_bitmap.data[0]);
1733 - return 1;
1711 + if(found_set != expected_set) {
1712 + fprintf(stderr, " >>> %s(): %s, bit %u is expected %s but found %s\n",
1713 + __FUNCTION__, msg, idx, expected_set?"SET":"UNSET", found_set?"SET":"UNSET");
1714 + errors++;
1715 + }
1716 }
1717
1736 - if (test_bitmap.data[1] == 0xffffffffffffffff)
1737 - fprintf(stderr, "%s() INDEX 1 is fully set OK\n", __FUNCTION__);
1738 - else {
1739 - fprintf(stderr, "%s() INDEX 1 is %"PRIu64" expected 0xffffffffffffffff\n", __FUNCTION__, test_bitmap.data[0]);
1740 - return 1;
1741 - }
1718 + if(errors)
1719 + fprintf(stderr,"%s(): %s, found %d errors\n",
1720 + __FUNCTION__, msg, errors);
1721
1743 - if (test_bitmap.data[2] == 0xffffffffffffffff)
1744 - fprintf(stderr, "%s() INDEX 2 is fully set OK\n", __FUNCTION__);
1745 - else {
1746 - fprintf(stderr, "%s() INDEX 2 is %"PRIu64" expected 0xffffffffffffffff\n", __FUNCTION__, test_bitmap.data[0]);
1747 - return 1;
1748 - }
1722 + return errors;
1723 +}
1724
1750 - if (test_bitmap.data[3] == 0xffffffffffffffff)
1751 - fprintf(stderr, "%s() INDEX 3 is fully set OK\n", __FUNCTION__);
1752 - else {
1753 - fprintf(stderr, "%s() INDEX 3 is %"PRIu64" expected 0xffffffffffffffff\n", __FUNCTION__, test_bitmap.data[0]);
1754 - return 1;
1755 - }
1725 +#define bitmapX_set_bit_and_track(ptr, bit, value, expected) do { \
1726 + bitmapX_set_bit(ptr, bit, value); \
1727 + (expected)[bit] = value; \
1728 +} while(0)
1729
1757 - i = 0;
1758 - j = 0;
1759 - do {
1760 - bitmap256_set_bit(&test_bitmap, i++, 0);
1761 - j++;
1762 - } while (j < 256);
1730 +int unit_test_bitmaps(void) {
1731 + fprintf(stderr, "%s() running...\n", __FUNCTION__ );
1732
1764 - if (test_bitmap.data[0] == 0)
1765 - fprintf(stderr, "%s() INDEX 0 is reset OK\n", __FUNCTION__);
1766 - else {
1767 - fprintf(stderr, "%s() INDEX 0 is not reset FAILED\n", __FUNCTION__);
1768 - return 1;
1769 - }
1770 - if (test_bitmap.data[1] == 0)
1771 - fprintf(stderr, "%s() INDEX 1 is reset OK\n", __FUNCTION__);
1772 - else {
1773 - fprintf(stderr, "%s() INDEX 1 is not reset FAILED\n", __FUNCTION__);
1774 - return 1;
1775 - }
1733 + int errors = 0;
1734
1777 - if (test_bitmap.data[2] == 0)
1778 - fprintf(stderr, "%s() INDEX 2 is reset OK\n", __FUNCTION__);
1779 - else {
1780 - fprintf(stderr, "%s() INDEX 2 is not reset FAILED\n", __FUNCTION__);
1781 - return 1;
1782 - }
1735 + char expected[8192];
1736
1784 - if (test_bitmap.data[3] == 0)
1785 - fprintf(stderr, "%s() INDEX 3 is reset OK\n", __FUNCTION__);
1786 - else {
1787 - fprintf(stderr, "%s() INDEX 3 is not reset FAILED\n", __FUNCTION__);
1788 - return 1;
1789 - }
1737 + BITMAP256 bmp256 = BITMAP256_INITIALIZER;
1738 + BITMAP1024 bmp1024 = BITMAP1024_INITIALIZER;
1739 + BITMAPX *bmp = NULL;
1740
1791 - i=0;
1792 - j = 0;
1793 - do {
1794 - bitmap256_set_bit(&test_bitmap, i, 1);
1795 - i += 4;
1796 - j += 4;
1797 - } while (j < 256);
1741 + for(int x = 0; x < 3 ; x++) {
1742 + char msg[100 + 1];
1743
1799 - if (test_bitmap.data[0] == 0x1111111111111111)
1800 - fprintf(stderr, "%s() INDEX 0 is 0x1111111111111111 set OK\n", __FUNCTION__);
1801 - else {
1802 - fprintf(stderr, "%s() INDEX 0 is %"PRIu64" expected 0x1111111111111111\n", __FUNCTION__, test_bitmap.data[0]);
1803 - return 1;
1804 - }
1744 + switch (x) {
1745 + default:
1746 + case 0:
1747 + bmp = (BITMAPX *) &bmp256;
1748 + break;
1749
1806 - if (test_bitmap.data[1] == 0x1111111111111111)
1807 - fprintf(stderr, "%s() INDEX 1 is 0x1111111111111111 set OK\n", __FUNCTION__);
1808 - else {
1809 - fprintf(stderr, "%s() INDEX 1 is %"PRIu64" expected 0x1111111111111111\n", __FUNCTION__, test_bitmap.data[1]);
1810 - return 1;
1811 - }
1750 + case 1:
1751 + bmp = (BITMAPX *) &bmp1024;
1752 + break;
1753
1813 - if (test_bitmap.data[2] == 0x1111111111111111)
1814 - fprintf(stderr, "%s() INDEX 2 is 0x1111111111111111 set OK\n", __FUNCTION__);
1815 - else {
1816 - fprintf(stderr, "%s() INDEX 2 is %"PRIu64" expected 0x1111111111111111\n", __FUNCTION__, test_bitmap.data[2]);
1817 - return 1;
1818 - }
1754 + case 2:
1755 + bmp = bitmapX_create(8192);
1756 + break;
1757 + }
1758
1820 - if (test_bitmap.data[3] == 0x1111111111111111)
1821 - fprintf(stderr, "%s() INDEX 3 is 0x1111111111111111 set OK\n", __FUNCTION__);
1822 - else {
1823 - fprintf(stderr, "%s() INDEX 3 is %"PRIu64" expected 0x1111111111111111\n", __FUNCTION__, test_bitmap.data[3]);
1824 - return 1;
1759 + // reset
1760 + memset(expected, 0, bmp->bits);
1761 + memset(bmp->data, 0, bmp->bits / 8);
1762 +
1763 + snprintf(msg, 100, "TEST 1 BITMAP %u", bmp->bits);
1764 + bitmapX_set_bit_and_track(bmp, 0, true, expected);
1765 + errors += bitmapX_test(bmp, expected, msg);
1766 +
1767 + snprintf(msg, 100, "TEST 2 BITMAP %u", bmp->bits);
1768 + bitmapX_set_bit_and_track(bmp, 64, true, expected);
1769 + errors += bitmapX_test(bmp, expected, msg);
1770 +
1771 + snprintf(msg, 100, "TEST 3 BITMAP %u", bmp->bits);
1772 + bitmapX_set_bit_and_track(bmp, 128, true, expected);
1773 + errors += bitmapX_test(bmp, expected, msg);
1774 +
1775 + snprintf(msg, 100, "TEST 4 BITMAP %u", bmp->bits);
1776 + bitmapX_set_bit_and_track(bmp, 192, true, expected);
1777 + errors += bitmapX_test(bmp, expected, msg);
1778 +
1779 + for (uint32_t step = 1; step < 256; step++) {
1780 + snprintf(msg, 100, "TEST 5 (setting) BITMAP %u STEP %u", bmp->bits, step);
1781 +
1782 + // reset
1783 + memset(expected, 0, bmp->bits);
1784 + memset(bmp->data, 0, bmp->bits / 8);
1785 +
1786 + for (uint32_t i = 0; i < bmp->bits ; i += step)
1787 + bitmapX_set_bit_and_track(bmp, i, true, expected);
1788 +
1789 + errors += bitmapX_test(bmp, expected, msg);
1790 + }
1791 +
1792 + for (uint32_t step = 1; step < 256; step++) {
1793 + snprintf(msg, 100, "TEST 6 (clearing) BITMAP %u STEP %u", bmp->bits, step);
1794 +
1795 + // reset
1796 + memset(expected, 0, bmp->bits);
1797 + memset(bmp->data, 0, bmp->bits / 8);
1798 +
1799 + for (uint32_t i = 0; i < bmp->bits ; i++)
1800 + bitmapX_set_bit_and_track(bmp, i, true, expected);
1801 +
1802 + for (uint32_t i = 0; i < bmp->bits ; i += step)
1803 + bitmapX_set_bit_and_track(bmp, i, false, expected);
1804 +
1805 + errors += bitmapX_test(bmp, expected, msg);
1806 + }
1807 }
1808
1827 - fprintf(stderr, "%s() tests passed\n", __FUNCTION__);
1828 - return 0;
1809 + freez(bmp);
1810 +
1811 + fprintf(stderr, "%s() %d errors\n", __FUNCTION__, errors);
1812 + return errors;
1813 }
1814
1815 #ifdef ENABLE_DBENGINE
daemon/unit_test.h
+1 -1
@@ -12,7 +12,7 @@ int unit_test_str2ld(void);
12 int unit_test_buffer(void);
13 int unit_test_static_threads(void);
14 int test_sqlite(void);
15 -int unit_test_bitmap256(void);
15 +int unit_test_bitmaps(void);
16 #ifdef ENABLE_DBENGINE
17 int test_dbengine(void);
18 void generate_dbengine_dataset(unsigned history_seconds);
database/contexts/api_v2.c
+776 -332
@@ -7,6 +7,89 @@
7 // ----------------------------------------------------------------------------
8 // /api/v2/contexts API
9
10 +struct alert_transitions_facets alert_transition_facets[] = {
11 + [ATF_STATUS] = {
12 + .id = "status",
13 + .name = "Alert Status",
14 + .query_param = "status",
15 + .order = 1,
16 + },
17 + [ATF_TYPE] = {
18 + .id = "type",
19 + .name = "Alert Type",
20 + .query_param = "type",
21 + .order = 2,
22 + },
23 + [ATF_ROLE] = {
24 + .id = "role",
25 + .name = "Recipient Role",
26 + .query_param = "role",
27 + .order = 3,
28 + },
29 + [ATF_CLASS] = {
30 + .id = "class",
31 + .name = "Alert Class",
32 + .query_param = "class",
33 + .order = 4,
34 + },
35 + [ATF_COMPONENT] = {
36 + .id = "component",
37 + .name = "Alert Component",
38 + .query_param = "component",
39 + .order = 5,
40 + },
41 + [ATF_NODE] = {
42 + .id = "node",
43 + .name = "Alert Node",
44 + .query_param = "node",
45 + .order = 6,
46 + },
47 +
48 + // terminator
49 + [ATF_TOTAL_ENTRIES] = {
50 + .id = NULL,
51 + .name = NULL,
52 + .query_param = NULL,
53 + .order = 9999,
54 + }
55 +};
56 +
57 +struct facet_entry {
58 + uint32_t count;
59 +};
60 +
61 +struct alert_transitions_callback_data {
62 + struct rrdcontext_to_json_v2_data *ctl;
63 + BUFFER *wb;
64 + bool debug;
65 + bool only_one_config;
66 +
67 + struct {
68 + SIMPLE_PATTERN *pattern;
69 + DICTIONARY *dict;
70 + } facets[ATF_TOTAL_ENTRIES];
71 +
72 + uint32_t limit;
73 + uint32_t items;
74 +
75 + struct sql_alert_transition_data *base; // double linked list - last item is base->prev
76 + struct sql_alert_transition_data *last_added; // the last item added, not the last of the list
77 +
78 + struct {
79 + size_t items;
80 + size_t first;
81 + size_t skips_before;
82 + size_t skips_after;
83 + size_t backwards;
84 + size_t forwards;
85 + size_t prepend;
86 + size_t append;
87 + size_t shifts;
88 + } stats;
89 +
90 + uint32_t configs_added;
91 +};
92 +
93 typedef enum __attribute__ ((__packed__)) {
94 FTS_MATCHED_NONE = 0,
95 FTS_MATCHED_HOST,
@@ -93,14 +176,6 @@ struct alert_v2_entry {
176 DICTIONARY *configs;
177 };
178
96 -struct alert_config_v2_entry {
97 - RRDCALC *tmp;
98 -
99 - size_t ati;
100 - size_t aci;
101 - size_t alerts_using_this;
102 -};
103 -
179 typedef struct full_text_search_index {
180 size_t searches;
181 size_t string_searches;
@@ -153,12 +228,9 @@ struct rrdcontext_to_json_v2_data {
228 time_t alarm_id_filter;
229
230 size_t ati;
156 - size_t aii;
157 - size_t aci;
231
232 DICTIONARY *alerts;
233 DICTIONARY *alert_instances;
161 - DICTIONARY *alert_configs;
234 } alerts;
235
236 struct {
@@ -243,32 +315,18 @@ static void alerts_v2_delete_callback(const DICTIONARY_ITEM *item __maybe_unused
315 dictionary_destroy(t->configs);
316 }
317
246 -static void alert_configs_v2_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data) {
247 - struct rrdcontext_to_json_v2_data *ctl = data;
248 - struct alert_config_v2_entry *t = value;
249 - t->aci = ctl->alerts.aci++;
250 - t->alerts_using_this = 1;
251 -}
252 -
253 -static bool alert_configs_v2_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value __maybe_unused, void *new_value __maybe_unused, void *data __maybe_unused) {
254 - struct alert_config_v2_entry *t = old_value;
255 - t->alerts_using_this++;
256 - return false;
257 -}
258 -
259 -static void alert_configs_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value __maybe_unused, void *data __maybe_unused) {
260 - ;
261 -}
262 -
318 static void alert_instances_v2_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data) {
319 struct rrdcontext_to_json_v2_data *ctl = data;
265 - struct alert_instance_v2_entry *t = value;
320 + struct sql_alert_instance_v2_entry *t = value;
321 RRDCALC *rc = t->tmp;
322
323 + t->context = rc->rrdset->context;
324 t->chart_id = rc->rrdset->id;
325 t->chart_name = rc->rrdset->name;
326 t->family = rc->rrdset->family;
327 + t->units = rc->units;
328 t->name = rc->name;
329 + t->source = rc->source;
330 t->status = rc->status;
331 t->flags = rc->run_flags;
332 t->info = rc->info;
@@ -281,7 +339,6 @@ static void alert_instances_v2_insert_callback(const DICTIONARY_ITEM *item __may
339 t->ni = ctl->nodes.ni;
340 t->global_id = rc->ae ? rc->ae->global_id : 0;
341 t->name = rc->name;
284 - t->aii = ctl->alerts.aii++;
342
343 uuid_copy(t->config_hash_id, rc->config_hash_id);
344 if(rc->ae)
@@ -418,28 +475,14 @@ static bool rrdcontext_matches_alert(struct rrdcontext_to_json_v2_data *ctl, RRD
475 struct alert_v2_entry *a2e = dictionary_set(ctl->alerts.alerts, string2str(rcl->name), &t,
476 sizeof(struct alert_v2_entry));
477 size_t ati = a2e->ati;
421 - size_t aci = 0;
478 matches++;
479
424 - if (ctl->options & CONTEXT_V2_OPTION_ALERT_CONFIGURATIONS) {
425 - char key[UUID_STR_LEN + 1];
426 - uuid_unparse_lower(rcl->config_hash_id, key);
427 - struct alert_config_v2_entry t2 = {
428 - .tmp = rcl,
429 - .ati = a2e->ati,
430 - };
431 - struct alert_config_v2_entry *a2c = dictionary_set(ctl->alerts.alert_configs, key, &t2,
432 - sizeof(struct alert_config_v2_entry));
433 - aci = a2c->aci;
434 - }
435 -
436 - if (ctl->options & CONTEXT_V2_OPTION_ALERT_INSTANCES) {
480 + if (ctl->options & (CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES | CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)) {
481 char key[20 + 1];
482 snprintfz(key, 20, "%p", rcl);
483
440 - struct alert_instance_v2_entry z = {
484 + struct sql_alert_instance_v2_entry z = {
485 .ati = ati,
442 - .aci = aci,
486 .tmp = rcl,
487 };
488 dictionary_set(ctl->alerts.alert_instances, key, &z, sizeof(z));
@@ -676,9 +719,9 @@ static inline void rrdhost_health_to_json_v2(BUFFER *wb, const char *key, RRDHOS
719 static void rrdcontext_to_json_v2_rrdhost(BUFFER *wb, RRDHOST *host, struct rrdcontext_to_json_v2_data *ctl, size_t node_id) {
720 buffer_json_add_array_item_object(wb); // this node
721 buffer_json_node_add_v2(wb, host, node_id, 0,
679 - (ctl->mode & CONTEXTS_V2_AGENTS) && !(ctl->mode & CONTEXTS_V2_NODES_INSTANCES));
722 + (ctl->mode & CONTEXTS_V2_AGENTS) && !(ctl->mode & CONTEXTS_V2_NODE_INSTANCES));
723
681 - if(ctl->mode & (CONTEXTS_V2_NODES_INFO | CONTEXTS_V2_NODES_INSTANCES)) {
724 + if(ctl->mode & (CONTEXTS_V2_NODES_INFO | CONTEXTS_V2_NODE_INSTANCES)) {
725 RRDHOST_STATUS s;
726 rrdhost_status(host, ctl->now, &s);
727
@@ -724,7 +767,7 @@ static void rrdcontext_to_json_v2_rrdhost(BUFFER *wb, RRDHOST *host, struct rrdc
767 agent_capabilities_to_json(wb, host, "capabilities");
768 }
769
727 - if (ctl->mode & (CONTEXTS_V2_NODES_INSTANCES)) {
770 + if (ctl->mode & (CONTEXTS_V2_NODE_INSTANCES)) {
771 buffer_json_member_add_array(wb, "instances");
772 buffer_json_add_array_item_object(wb); // this instance
773 {
@@ -795,7 +838,7 @@ static ssize_t rrdcontext_to_json_v2_add_host(void *data, RRDHOST *host, bool qu
838 return -1; // stop the query
839
840 bool host_matched = (ctl->mode & CONTEXTS_V2_NODES);
798 - bool do_contexts = (ctl->mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS));
841 + bool do_contexts = (ctl->mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_ALERTS));
842
843 ctl->q.host_match = FTS_MATCHED_NONE;
844 if((ctl->mode & CONTEXTS_V2_SEARCH)) {
@@ -875,7 +918,7 @@ static void buffer_json_contexts_v2_mode_to_array(BUFFER *wb, const char *key, C
918 if(mode & CONTEXTS_V2_NODES_INFO)
919 buffer_json_add_array_item_string(wb, "nodes-info");
920
878 - if(mode & CONTEXTS_V2_NODES_INSTANCES)
921 + if(mode & CONTEXTS_V2_NODE_INSTANCES)
922 buffer_json_add_array_item_string(wb, "nodes-instances");
923
924 if(mode & CONTEXTS_V2_CONTEXTS)
@@ -887,6 +930,9 @@ static void buffer_json_contexts_v2_mode_to_array(BUFFER *wb, const char *key, C
930 if(mode & CONTEXTS_V2_ALERTS)
931 buffer_json_add_array_item_string(wb, "alerts");
932
933 + if(mode & CONTEXTS_V2_ALERT_TRANSITIONS)
934 + buffer_json_add_array_item_string(wb, "alert_transitions");
935 +
936 buffer_json_array_close(wb);
937 }
938
@@ -905,6 +951,8 @@ void buffer_json_query_timings(BUFFER *wb, const char *key, struct query_timings
951 buffer_json_object_close(wb);
952 }
953
954 +void build_info_to_json_object(BUFFER *b);
955 +
956 void buffer_json_agents_array_v2(BUFFER *wb, struct query_timings *timings, time_t now_s, bool info) {
957 if(!now_s)
958 now_s = now_realtime_sec();
@@ -918,31 +966,11 @@ void buffer_json_agents_array_v2(BUFFER *wb, struct query_timings *timings, time
966 buffer_json_member_add_uint64(wb, "ai", 0);
967
968 if(info) {
921 - buffer_json_member_add_string(wb, "v", string2str(localhost->program_version));
922 -
923 - buffer_json_member_add_object(wb, "cloud");
924 - {
925 - size_t id = cloud_connection_id();
926 - CLOUD_STATUS status = cloud_status();
927 - time_t last_change = cloud_last_change();
928 - time_t next_connect = cloud_next_connection_attempt();
929 - buffer_json_member_add_uint64(wb, "id", id);
930 - buffer_json_member_add_string(wb, "status", cloud_status_to_string(status));
931 - buffer_json_member_add_time_t(wb, "since", last_change);
932 - buffer_json_member_add_time_t(wb, "age", now_s - last_change);
933 -
934 - if (status != CLOUD_STATUS_ONLINE)
935 - buffer_json_member_add_string(wb, "reason", cloud_offline_reason());
936 -
937 - if (status == CLOUD_STATUS_OFFLINE && next_connect > now_s) {
938 - buffer_json_member_add_time_t(wb, "next_check", next_connect);
939 - buffer_json_member_add_time_t(wb, "next_in", next_connect - now_s);
940 - }
969 + buffer_json_member_add_object(wb, "application");
970 + build_info_to_json_object(wb);
971 + buffer_json_object_close(wb); // netdata
972
942 - if (status != CLOUD_STATUS_DISABLED && cloud_base_url())
943 - buffer_json_member_add_string(wb, "url", cloud_base_url());
944 - }
945 - buffer_json_object_close(wb); // cloud
973 + buffer_json_cloud_status(wb, now_s);
974
975 buffer_json_member_add_array(wb, "db_size");
976 for (size_t tier = 0; tier < storage_tiers; tier++) {
@@ -951,6 +979,9 @@ void buffer_json_agents_array_v2(BUFFER *wb, struct query_timings *timings, time
979
980 size_t max = storage_engine_disk_space_max(eng->backend, localhost->db[tier].instance);
981 size_t used = storage_engine_disk_space_used(eng->backend, localhost->db[tier].instance);
982 + time_t first_time_s = storage_engine_global_first_time_s(eng->backend, localhost->db[tier].instance);
983 + size_t currently_collected_metrics = storage_engine_collected_metrics(eng->backend, localhost->db[tier].instance);
984 +
985 NETDATA_DOUBLE percent;
986 if (used && max)
987 percent = (NETDATA_DOUBLE) used * 100.0 / (NETDATA_DOUBLE) max;
@@ -959,9 +990,26 @@ void buffer_json_agents_array_v2(BUFFER *wb, struct query_timings *timings, time
990
991 buffer_json_add_array_item_object(wb);
992 buffer_json_member_add_uint64(wb, "tier", tier);
962 - buffer_json_member_add_uint64(wb, "disk_used", used);
963 - buffer_json_member_add_uint64(wb, "disk_max", max);
964 - buffer_json_member_add_double(wb, "disk_percent", percent);
993 +
994 + if(used || max) {
995 + buffer_json_member_add_uint64(wb, "disk_used", used);
996 + buffer_json_member_add_uint64(wb, "disk_max", max);
997 + buffer_json_member_add_double(wb, "disk_percent", percent);
998 + }
999 +
1000 + if(first_time_s) {
1001 + buffer_json_member_add_time_t(wb, "from", first_time_s);
1002 + buffer_json_member_add_time_t(wb, "to", now_s);
1003 + buffer_json_member_add_time_t(wb, "retention", now_s - first_time_s);
1004 +
1005 + if(used || max) // we have disk space information
1006 + buffer_json_member_add_time_t(wb, "expected_retention",
1007 + (time_t) ((NETDATA_DOUBLE) (now_s - first_time_s) * 100.0 / percent));
1008 + }
1009 +
1010 + if(currently_collected_metrics)
1011 + buffer_json_member_add_uint64(wb, "currently_collected_metrics", currently_collected_metrics);
1012 +
1013 buffer_json_object_close(wb);
1014 }
1015 buffer_json_array_close(wb); // db_size
@@ -1090,6 +1138,562 @@ static void rrdcontext_v2_set_transition_filter(const char *machine_guid, const
1138 ctl->alerts.alarm_id_filter = alarm_id;
1139 }
1140
1141 +struct alert_instances_callback_data {
1142 + BUFFER *wb;
1143 + struct rrdcontext_to_json_v2_data *ctl;
1144 + bool debug;
1145 +};
1146 +
1147 +static void contexts_v2_alert_config_to_json_from_sql_alert_config_data(struct sql_alert_config_data *t, void *data) {
1148 + struct alert_transitions_callback_data *d = data;
1149 + BUFFER *wb = d->wb;
1150 + bool debug = d->debug;
1151 + d->configs_added++;
1152 +
1153 + if(d->only_one_config)
1154 + buffer_json_add_array_item_object(wb); // alert config
1155 +
1156 + {
1157 + buffer_json_member_add_string(wb, "name", t->name);
1158 + buffer_json_member_add_uuid(wb, "config_hash_id", t->config_hash_id);
1159 +
1160 + buffer_json_member_add_object(wb, "selectors");
1161 + {
1162 + bool is_template = t->selectors.on_template && *t->selectors.on_template ? true : false;
1163 + buffer_json_member_add_string(wb, "type", is_template ? "template" : "alarm");
1164 + buffer_json_member_add_string(wb, "on", is_template ? t->selectors.on_template : t->selectors.on_key);
1165 +
1166 + buffer_json_member_add_string(wb, "os", t->selectors.os);
1167 + buffer_json_member_add_string(wb, "hosts", t->selectors.hosts);
1168 + buffer_json_member_add_string(wb, "families", t->selectors.families);
1169 + buffer_json_member_add_string(wb, "plugin", t->selectors.plugin);
1170 + buffer_json_member_add_string(wb, "module", t->selectors.module);
1171 + buffer_json_member_add_string(wb, "host_labels", t->selectors.host_labels);
1172 + buffer_json_member_add_string(wb, "chart_labels", t->selectors.chart_labels);
1173 + buffer_json_member_add_string(wb, "charts", t->selectors.charts);
1174 + }
1175 + buffer_json_object_close(wb); // selectors
1176 +
1177 + buffer_json_member_add_object(wb, "value"); // value
1178 + {
1179 + // buffer_json_member_add_string(wb, "every", t->value.every); // does not exist in Netdata Cloud
1180 + buffer_json_member_add_string(wb, "units", t->value.units);
1181 + buffer_json_member_add_uint64(wb, "update_every", t->value.update_every);
1182 +
1183 + if (t->value.db.after || debug) {
1184 + buffer_json_member_add_object(wb, "db");
1185 + {
1186 + // buffer_json_member_add_string(wb, "lookup", t->value.db.lookup); // does not exist in Netdata Cloud
1187 +
1188 + buffer_json_member_add_time_t(wb, "after", t->value.db.after);
1189 + buffer_json_member_add_time_t(wb, "before", t->value.db.before);
1190 + buffer_json_member_add_string(wb, "method", t->value.db.method);
1191 + buffer_json_member_add_string(wb, "dimensions", t->value.db.dimensions);
1192 + web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options",(RRDR_OPTIONS) t->value.db.options);
1193 + }
1194 + buffer_json_object_close(wb); // db
1195 + }
1196 +
1197 + if (t->value.calc || debug)
1198 + buffer_json_member_add_string(wb, "calc", t->value.calc);
1199 + }
1200 + buffer_json_object_close(wb); // value
1201 +
1202 + if (t->status.warn || t->status.crit || debug) {
1203 + buffer_json_member_add_object(wb, "status"); // status
1204 + {
1205 + NETDATA_DOUBLE green = t->status.green ? str2ndd(t->status.green, NULL) : NAN;
1206 + NETDATA_DOUBLE red = t->status.red ? str2ndd(t->status.red, NULL) : NAN;
1207 +
1208 + if (!isnan(green) || debug)
1209 + buffer_json_member_add_double(wb, "green", green);
1210 +
1211 + if (!isnan(red) || debug)
1212 + buffer_json_member_add_double(wb, "red", red);
1213 +
1214 + if (t->status.warn || debug)
1215 + buffer_json_member_add_string(wb, "warn", t->status.warn);
1216 +
1217 + if (t->status.crit || debug)
1218 + buffer_json_member_add_string(wb, "crit", t->status.crit);
1219 + }
1220 + buffer_json_object_close(wb); // status
1221 + }
1222 +
1223 + buffer_json_member_add_object(wb, "notification");
1224 + {
1225 + buffer_json_member_add_string(wb, "type", "agent");
1226 + buffer_json_member_add_string(wb, "exec", t->notification.exec ? t->notification.exec : NULL);
1227 + buffer_json_member_add_string(wb, "to", t->notification.to_key ? t->notification.to_key : string2str(localhost->health.health_default_recipient));
1228 + buffer_json_member_add_string(wb, "delay", t->notification.delay);
1229 + buffer_json_member_add_string(wb, "repeat", t->notification.repeat);
1230 + buffer_json_member_add_string(wb, "options", t->notification.options);
1231 + }
1232 + buffer_json_object_close(wb); // notification
1233 +
1234 + buffer_json_member_add_string(wb, "class", t->classification);
1235 + buffer_json_member_add_string(wb, "component", t->component);
1236 + buffer_json_member_add_string(wb, "type", t->type);
1237 + buffer_json_member_add_string(wb, "info", t->info);
1238 + // buffer_json_member_add_string(wb, "source", t->source); // moved to alert instance
1239 + }
1240 +
1241 + if(d->only_one_config)
1242 + buffer_json_object_close(wb);
1243 +}
1244 +
1245 +int contexts_v2_alert_config_to_json(struct web_client *w, const char *config_hash_id) {
1246 + struct alert_transitions_callback_data data = {
1247 + .wb = w->response.data,
1248 + .debug = false,
1249 + .only_one_config = false,
1250 + };
1251 + DICTIONARY *configs = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
1252 + dictionary_set(configs, config_hash_id, NULL, 0);
1253 +
1254 + buffer_flush(w->response.data);
1255 +
1256 + buffer_json_initialize(w->response.data, "\"", "\"", 0, true, false);
1257 +
1258 + int added = sql_get_alert_configuration(configs, contexts_v2_alert_config_to_json_from_sql_alert_config_data, &data, false);
1259 + buffer_json_finalize(w->response.data);
1260 +
1261 + int ret = HTTP_RESP_OK;
1262 +
1263 + if(added <= 0) {
1264 + buffer_flush(w->response.data);
1265 + w->response.data->content_type = CT_TEXT_PLAIN;
1266 + if(added < 0) {
1267 + buffer_strcat(w->response.data, "Failed to execute SQL query.");
1268 + ret = HTTP_RESP_INTERNAL_SERVER_ERROR;
1269 + }
1270 + else {
1271 + buffer_strcat(w->response.data, "Config is not found.");
1272 + ret = HTTP_RESP_NOT_FOUND;
1273 + }
1274 + }
1275 +
1276 + return ret;
1277 +}
1278 +
1279 +static int contexts_v2_alert_instance_to_json_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data) {
1280 + struct sql_alert_instance_v2_entry *t = value;
1281 + struct alert_instances_callback_data *d = data;
1282 + struct rrdcontext_to_json_v2_data *ctl = d->ctl; (void)ctl;
1283 + bool debug = d->debug; (void)debug;
1284 + BUFFER *wb = d->wb;
1285 +
1286 + buffer_json_add_array_item_object(wb);
1287 + {
1288 + buffer_json_member_add_uint64(wb, "ni", t->ni);
1289 +
1290 + buffer_json_member_add_string(wb, "nm", string2str(t->name));
1291 + buffer_json_member_add_string(wb, "ch", string2str(t->chart_name));
1292 +
1293 + if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES) {
1294 + if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY)
1295 + buffer_json_member_add_uint64(wb, "ati", t->ati);
1296 +
1297 + buffer_json_member_add_string(wb, "units", string2str(t->units));
1298 + buffer_json_member_add_string(wb, "fami", string2str(t->family));
1299 + buffer_json_member_add_string(wb, "info", string2str(t->info));
1300 + buffer_json_member_add_string(wb, "ctx", string2str(t->context));
1301 + buffer_json_member_add_string(wb, "st", rrdcalc_status2string(t->status));
1302 + buffer_json_member_add_uuid(wb, "tr_i", &t->last_transition_id);
1303 + buffer_json_member_add_double(wb, "tr_v", t->last_status_change_value);
1304 + buffer_json_member_add_time_t(wb, "tr_t", t->last_status_change);
1305 + buffer_json_member_add_uuid(wb, "cfg", &t->config_hash_id);
1306 + buffer_json_member_add_string(wb, "src", string2str(t->source));
1307 +
1308 + // Agent specific fields
1309 + buffer_json_member_add_uint64(wb, "gi", t->global_id);
1310 + // rrdcalc_flags_to_json_array (wb, "flags", t->flags);
1311 + }
1312 +
1313 + if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_VALUES) {
1314 + // Netdata Cloud fetched these by querying the agents
1315 + buffer_json_member_add_double(wb, "v", t->value);
1316 + buffer_json_member_add_time_t(wb, "t", t->last_updated);
1317 + }
1318 + }
1319 + buffer_json_object_close(wb); // alert instance
1320 +
1321 + return 1;
1322 +}
1323 +
1324 +static void contexts_v2_alert_instances_to_json(BUFFER *wb, const char *key, struct rrdcontext_to_json_v2_data *ctl, bool debug) {
1325 + buffer_json_member_add_array(wb, key);
1326 + {
1327 + struct alert_instances_callback_data data = {
1328 + .wb = wb,
1329 + .ctl = ctl,
1330 + .debug = debug,
1331 + };
1332 + dictionary_walkthrough_rw(ctl->alerts.alert_instances, DICTIONARY_LOCK_READ,
1333 + contexts_v2_alert_instance_to_json_callback, &data);
1334 + }
1335 + buffer_json_array_close(wb); // alerts_instances
1336 +}
1337 +
1338 +static void contexts_v2_alerts_to_json(BUFFER *wb, struct rrdcontext_to_json_v2_data *ctl, bool debug) {
1339 + if(ctl->request->options & CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY) {
1340 + buffer_json_member_add_array(wb, "alerts");
1341 + {
1342 + struct alert_v2_entry *t;
1343 + dfe_start_read(ctl->alerts.alerts, t)
1344 + {
1345 + buffer_json_add_array_item_object(wb);
1346 + {
1347 + buffer_json_member_add_uint64(wb, "ati", t->ati);
1348 + buffer_json_member_add_string(wb, "nm", string2str(t->name));
1349 +
1350 + buffer_json_member_add_uint64(wb, "cr", t->critical);
1351 + buffer_json_member_add_uint64(wb, "wr", t->warning);
1352 + buffer_json_member_add_uint64(wb, "cl", t->clear);
1353 + buffer_json_member_add_uint64(wb, "er", t->error);
1354 +
1355 + buffer_json_member_add_uint64(wb, "in", t->instances);
1356 + buffer_json_member_add_uint64(wb, "nd", dictionary_entries(t->nodes));
1357 + buffer_json_member_add_uint64(wb, "cfg", dictionary_entries(t->configs));
1358 + }
1359 + buffer_json_object_close(wb); // alert name
1360 + }
1361 + dfe_done(t);
1362 + }
1363 + buffer_json_array_close(wb); // alerts
1364 + }
1365 +
1366 + if(ctl->request->options & (CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES|CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)) {
1367 + contexts_v2_alert_instances_to_json(wb, "alert_instances", ctl, debug);
1368 + }
1369 +}
1370 +
1371 +static struct sql_alert_transition_data *contexts_v2_alert_transition_dup(struct sql_alert_transition_data *t, const char *machine_guid) {
1372 + struct sql_alert_transition_data *n = mallocz(sizeof(*t));
1373 + memcpy(n, t, sizeof(*t));
1374 +
1375 + n->transition_id = mallocz(sizeof(*t->transition_id));
1376 + memcpy(n->transition_id, t->transition_id, sizeof(*t->transition_id));
1377 +
1378 + n->host_id = NULL;
1379 +
1380 + n->config_hash_id = mallocz(sizeof(*t->config_hash_id));
1381 + memcpy(n->config_hash_id, t->config_hash_id, sizeof(*t->config_hash_id));
1382 +
1383 + n->alert_name = t->alert_name && *t->alert_name ? strdupz(t->alert_name) : NULL;
1384 + n->chart = t->chart && *t->chart ? strdupz(t->chart) : NULL;
1385 + n->chart_context = t->chart_context && *t->chart_context ? strdupz(t->chart_context) : NULL;
1386 + n->family = NULL;
1387 + n->recipient = t->recipient && *t->recipient ? strdupz(t->recipient) : NULL;
1388 + n->units = t->units && *t->units ? strdupz(t->units) : NULL;
1389 + n->info = t->info && *t->info ? strdupz(t->info) : NULL;
1390 + n->classification = t->classification && *t->classification ? strdupz(t->classification) : NULL;
1391 + n->type = t->type && *t->type ? strdupz(t->type) : NULL;
1392 + n->component = t->component && *t->component ? strdupz(t->component) : NULL;
1393 + n->exec = (t->exec && *t->exec) ? strdupz(t->exec) : NULL;
1394 +
1395 + memcpy(n->machine_guid, machine_guid, sizeof(n->machine_guid));
1396 +
1397 + return n;
1398 +}
1399 +
1400 +static void contexts_v2_alert_transition_free(struct sql_alert_transition_data *t) {
1401 + freez(t->transition_id);
1402 + freez(t->host_id);
1403 + freez(t->config_hash_id);
1404 + freez((void *)t->alert_name);
1405 + freez((void *)t->chart);
1406 + freez((void *)t->chart_context);
1407 + freez((void *)t->family);
1408 + freez((void *)t->recipient);
1409 + freez((void *)t->units);
1410 + freez((void *)t->info);
1411 + freez((void *)t->classification);
1412 + freez((void *)t->type);
1413 + freez((void *)t->component);
1414 + freez((void *)t->exec);
1415 + freez(t);
1416 +}
1417 +
1418 +static inline void contexts_v2_alert_transition_keep(struct alert_transitions_callback_data *d, struct sql_alert_transition_data *t, const char *machine_guid) {
1419 + if(unlikely(t->global_id <= d->ctl->request->alerts.global_id_anchor)) {
1420 + // this is in our past, we are not interested
1421 + d->stats.skips_before++;
1422 + return;
1423 + }
1424 +
1425 + if(unlikely(!d->base)) {
1426 + d->last_added = contexts_v2_alert_transition_dup(t, machine_guid);
1427 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(d->base, d->last_added, prev, next);
1428 + d->items++;
1429 + d->stats.first++;
1430 + return;
1431 + }
1432 +
1433 + struct sql_alert_transition_data *last = d->last_added;
1434 + while(last != d->base && last->prev->global_id > t->global_id) {
1435 + last = last->prev;
1436 + d->stats.backwards++;
1437 + }
1438 +
1439 + while(last->next && last->next->global_id < t->global_id) {
1440 + last = last->next;
1441 + d->stats.forwards++;
1442 + }
1443 +
1444 + if(d->items >= d->limit && last == d->base->prev && last->global_id < t->global_id) {
1445 + d->stats.skips_after++;
1446 + return;
1447 + }
1448 +
1449 + d->items++;
1450 + d->last_added = contexts_v2_alert_transition_dup(t, machine_guid);
1451 +
1452 + if(last->global_id > t->global_id) {
1453 + DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(d->base, d->last_added, prev, next);
1454 + d->stats.prepend++;
1455 + }
1456 + else {
1457 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(d->base, d->last_added, prev, next);
1458 + d->stats.append++;
1459 + }
1460 +
1461 + while(d->items > d->limit) {
1462 + // we have to remove something
1463 +
1464 + struct sql_alert_transition_data *tmp = d->base->prev;
1465 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(d->base, tmp, prev, next);
1466 + d->items--;
1467 +
1468 + if(unlikely(d->last_added == tmp))
1469 + d->last_added = d->base;
1470 +
1471 + contexts_v2_alert_transition_free(tmp);
1472 +
1473 + d->stats.shifts++;
1474 + }
1475 +}
1476 +
1477 +static void contexts_v2_alert_transition_callback(struct sql_alert_transition_data *t, void *data) {
1478 + struct alert_transitions_callback_data *d = data;
1479 + d->stats.items++;
1480 +
1481 + char machine_guid[UUID_STR_LEN] = "";
1482 + uuid_unparse_lower(*t->host_id, machine_guid);
1483 +
1484 + const char *facets[ATF_TOTAL_ENTRIES] = {
1485 + [ATF_STATUS] = rrdcalc_status2string(t->new_status),
1486 + [ATF_CLASS] = t->classification,
1487 + [ATF_TYPE] = t->type,
1488 + [ATF_COMPONENT] = t->component,
1489 + [ATF_ROLE] = t->recipient && *t->recipient ? t->recipient : string2str(localhost->health.health_default_recipient),
1490 + [ATF_NODE] = machine_guid,
1491 + };
1492 +
1493 + for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
1494 + if (!facets[i] || !*facets[i]) facets[i] = "unknown";
1495 +
1496 + struct facet_entry tmp = {
1497 + .count = 0,
1498 + };
1499 + dictionary_set(d->facets[i].dict, facets[i], &tmp, sizeof(tmp));
1500 + }
1501 +
1502 + bool selected[ATF_TOTAL_ENTRIES] = { 0 };
1503 +
1504 + uint32_t selected_by = 0;
1505 + for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
1506 + selected[i] = !d->facets[i].pattern || simple_pattern_matches(d->facets[i].pattern, facets[i]);
1507 + if(selected[i])
1508 + selected_by++;
1509 + }
1510 +
1511 + if(selected_by == ATF_TOTAL_ENTRIES) {
1512 + // this item is selected by all facets
1513 + // put it in our result (if it fits)
1514 + contexts_v2_alert_transition_keep(d, t, machine_guid);
1515 + }
1516 +
1517 + if(selected_by >= ATF_TOTAL_ENTRIES - 1) {
1518 + // this item is selected by all, or all except one facet
1519 + // in both cases we need to add it to our counters
1520 +
1521 + for (size_t i = 0; i < ATF_TOTAL_ENTRIES; i++) {
1522 + uint32_t counted_by = selected_by;
1523 +
1524 + if (counted_by != ATF_TOTAL_ENTRIES) {
1525 + counted_by = 0;
1526 + for (size_t j = 0; j < ATF_TOTAL_ENTRIES; j++) {
1527 + if (i == j || selected[j])
1528 + counted_by++;
1529 + }
1530 + }
1531 +
1532 + if (counted_by == ATF_TOTAL_ENTRIES) {
1533 + // we need to count it on this facet
1534 + struct facet_entry *x = dictionary_get(d->facets[i].dict, facets[i]);
1535 + internal_fatal(!x, "facet is not found");
1536 + if(x)
1537 + x->count++;
1538 + }
1539 + }
1540 + }
1541 +}
1542 +
1543 +static void contexts_v2_alert_transitions_to_json(BUFFER *wb, struct rrdcontext_to_json_v2_data *ctl, bool debug) {
1544 + struct alert_transitions_callback_data data = {
1545 + .wb = wb,
1546 + .ctl = ctl,
1547 + .debug = debug,
1548 + .only_one_config = true,
1549 + .limit = ctl->request->alerts.last,
1550 + .items = 0,
1551 + .base = NULL,
1552 + };
1553 +
1554 + for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
1555 + data.facets[i].dict = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, sizeof(struct facet_entry));
1556 + if(ctl->request->alerts.facets[i])
1557 + data.facets[i].pattern = simple_pattern_create(ctl->request->alerts.facets[i], ",|", SIMPLE_PATTERN_EXACT, false);
1558 + }
1559 +
1560 + sql_alert_transitions(
1561 + ctl->nodes.dict,
1562 + ctl->window.after,
1563 + ctl->window.before,
1564 + ctl->request->contexts,
1565 + ctl->request->alerts.alert,
1566 + ctl->request->alerts.transition,
1567 + contexts_v2_alert_transition_callback,
1568 + &data,
1569 + debug);
1570 +
1571 + buffer_json_member_add_array(wb, "facets");
1572 + for (size_t i = 0; i < ATF_TOTAL_ENTRIES; i++) {
1573 + buffer_json_add_array_item_object(wb);
1574 + {
1575 + buffer_json_member_add_string(wb, "id", alert_transition_facets[i].id);
1576 + buffer_json_member_add_string(wb, "name", alert_transition_facets[i].name);
1577 + buffer_json_member_add_uint64(wb, "order", alert_transition_facets[i].order);
1578 + buffer_json_member_add_array(wb, "options");
1579 + {
1580 + struct facet_entry *x;
1581 + dfe_start_read(data.facets[i].dict, x) {
1582 + buffer_json_add_array_item_object(wb);
1583 + {
1584 + buffer_json_member_add_string(wb, "id", x_dfe.name);
1585 + if (i == ATF_NODE) {
1586 + RRDHOST *host = rrdhost_find_by_guid(x_dfe.name);
1587 + if (host)
1588 + buffer_json_member_add_string(wb, "name", rrdhost_hostname(host));
1589 + else
1590 + buffer_json_member_add_string(wb, "name", x_dfe.name);
1591 + } else
1592 + buffer_json_member_add_string(wb, "name", x_dfe.name);
1593 + buffer_json_member_add_uint64(wb, "count", x->count);
1594 + }
1595 + buffer_json_object_close(wb);
1596 + }
1597 + dfe_done(x);
1598 + }
1599 + buffer_json_array_close(wb); // options
1600 + }
1601 + buffer_json_object_close(wb); // facet
1602 + }
1603 + buffer_json_array_close(wb); // facets
1604 +
1605 + buffer_json_member_add_array(wb, "transitions");
1606 + for(struct sql_alert_transition_data *t = data.base; t ; t = t->next) {
1607 + buffer_json_add_array_item_object(wb);
1608 + {
1609 + buffer_json_member_add_uint64(wb, "gi", t->global_id);
1610 + buffer_json_member_add_uuid(wb, "transition_id", t->transition_id);
1611 + buffer_json_member_add_uuid(wb, "config_hash_id", t->config_hash_id);
1612 + buffer_json_member_add_string(wb, "machine_guid", t->machine_guid);
1613 + buffer_json_member_add_string(wb, "alert", t->alert_name);
1614 + buffer_json_member_add_string(wb, "instance", t->chart);
1615 + buffer_json_member_add_string(wb, "context", t->chart_context);
1616 + // buffer_json_member_add_string(wb, "family", t->family);
1617 + buffer_json_member_add_string(wb, "component", t->component);
1618 + buffer_json_member_add_string(wb, "classification", t->classification);
1619 + buffer_json_member_add_string(wb, "type", t->type);
1620 +
1621 + buffer_json_member_add_time_t(wb, "when", t->when_key);
1622 + buffer_json_member_add_string(wb, "info", t->info);
1623 + buffer_json_member_add_string(wb, "units", t->units);
1624 + buffer_json_member_add_object(wb, "new");
1625 + {
1626 + buffer_json_member_add_string(wb, "status", rrdcalc_status2string(t->new_status));
1627 + buffer_json_member_add_double(wb, "value", t->new_value);
1628 + }
1629 + buffer_json_object_close(wb); // new
1630 + buffer_json_member_add_object(wb, "old");
1631 + {
1632 + buffer_json_member_add_string(wb, "status", rrdcalc_status2string(t->old_status));
1633 + buffer_json_member_add_double(wb, "value", t->old_value);
1634 + buffer_json_member_add_time_t(wb, "duration", t->duration);
1635 + buffer_json_member_add_time_t(wb, "raised_duration", t->non_clear_duration);
1636 + }
1637 + buffer_json_object_close(wb); // old
1638 +
1639 + buffer_json_member_add_object(wb, "notification");
1640 + {
1641 + buffer_json_member_add_time_t(wb, "when", t->exec_run_timestamp);
1642 + buffer_json_member_add_time_t(wb, "delay", t->delay);
1643 + buffer_json_member_add_time_t(wb, "delay_up_to_time", t->delay_up_to_timestamp);
1644 + health_entry_flags_to_json_array(wb, "flags", t->flags);
1645 + buffer_json_member_add_string(wb, "exec", (t->exec && *t->exec) ? t->exec : string2str(localhost->health.health_default_exec));
1646 + buffer_json_member_add_uint64(wb, "exec_code", t->exec_code);
1647 + buffer_json_member_add_string(wb, "to", t->recipient && *t->recipient ? t->recipient : string2str(localhost->health.health_default_recipient));
1648 + }
1649 + buffer_json_object_close(wb); // notification
1650 + }
1651 + buffer_json_object_close(wb); // a transition
1652 + }
1653 + buffer_json_array_close(wb); // all transitions
1654 +
1655 + if(ctl->options & CONTEXT_V2_OPTION_ALERTS_WITH_CONFIGURATIONS) {
1656 + DICTIONARY *configs = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
1657 +
1658 + for(struct sql_alert_transition_data *t = data.base; t ; t = t->next) {
1659 + char guid[UUID_STR_LEN];
1660 + uuid_unparse_lower(*t->config_hash_id, guid);
1661 + dictionary_set(configs, guid, NULL, 0);
1662 + }
1663 +
1664 + buffer_json_member_add_array(wb, "configurations");
1665 + sql_get_alert_configuration(configs, contexts_v2_alert_config_to_json_from_sql_alert_config_data, &data, debug);
1666 + buffer_json_array_close(wb);
1667 +
1668 + dictionary_destroy(configs);
1669 + }
1670 +
1671 + while(data.base) {
1672 + struct sql_alert_transition_data *t = data.base;
1673 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(data.base, t, prev, next);
1674 + contexts_v2_alert_transition_free(t);
1675 + }
1676 +
1677 + for(size_t i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
1678 + dictionary_destroy(data.facets[i].dict);
1679 + simple_pattern_free(data.facets[i].pattern);
1680 + }
1681 +
1682 + buffer_json_member_add_object(wb, "stats");
1683 + {
1684 + buffer_json_member_add_uint64(wb, "items", data.stats.items);
1685 + buffer_json_member_add_uint64(wb, "first", data.stats.first);
1686 + buffer_json_member_add_uint64(wb, "prepend", data.stats.prepend);
1687 + buffer_json_member_add_uint64(wb, "append", data.stats.append);
1688 + buffer_json_member_add_uint64(wb, "backwards", data.stats.backwards);
1689 + buffer_json_member_add_uint64(wb, "forwards", data.stats.forwards);
1690 + buffer_json_member_add_uint64(wb, "shifts", data.stats.shifts);
1691 + buffer_json_member_add_uint64(wb, "skips_before", data.stats.skips_before);
1692 + buffer_json_member_add_uint64(wb, "skips_after", data.stats.skips_after);
1693 + }
1694 + buffer_json_object_close(wb);
1695 +}
1696 +
1697 int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTEXTS_V2_MODE mode) {
1698 int resp = HTTP_RESP_OK;
1699 bool run = true;
@@ -1100,8 +1704,21 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
1704 if(mode & (CONTEXTS_V2_AGENTS_INFO))
1705 mode |= CONTEXTS_V2_AGENTS;
1706
1103 - if(mode & (CONTEXTS_V2_ALERTS | CONTEXTS_V2_FUNCTIONS | CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_NODES_INFO | CONTEXTS_V2_NODES_INSTANCES))
1707 + if(mode & (CONTEXTS_V2_FUNCTIONS | CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_NODES_INFO | CONTEXTS_V2_NODE_INSTANCES))
1708 + mode |= CONTEXTS_V2_NODES;
1709 +
1710 + if(mode & CONTEXTS_V2_ALERTS) {
1711 + mode |= CONTEXTS_V2_NODES;
1712 + req->options &= ~CONTEXT_V2_OPTION_ALERTS_WITH_CONFIGURATIONS;
1713 +
1714 + if(!(req->options & (CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY|CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES|CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)))
1715 + req->options |= CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY;
1716 + }
1717 +
1718 + if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
1719 mode |= CONTEXTS_V2_NODES;
1720 + req->options &= ~CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES;
1721 + }
1722
1723 struct rrdcontext_to_json_v2_data ctl = {
1724 .wb = wb,
@@ -1154,7 +1771,7 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
1771
1772 if(mode & CONTEXTS_V2_ALERTS) {
1773 if(req->alerts.transition) {
1157 - ctl.options |= CONTEXT_V2_OPTION_ALERT_INSTANCES | CONTEXT_V2_OPTION_ALERT_CONFIGURATIONS | CONTEXT_V2_OPTION_ALERT_TRANSITIONS;
1774 + ctl.options |= CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES|CONTEXT_V2_OPTION_ALERTS_WITH_VALUES;
1775 run = sql_find_alert_transition(req->alerts.transition, rrdcontext_v2_set_transition_filter, &ctl);
1776 if(!run) {
1777 resp = HTTP_RESP_NOT_FOUND;
@@ -1169,28 +1786,19 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
1786 dictionary_register_conflict_callback(ctl.alerts.alerts, alerts_v2_conflict_callback, &ctl);
1787 dictionary_register_delete_callback(ctl.alerts.alerts, alerts_v2_delete_callback, &ctl);
1788
1172 - if(ctl.options & CONTEXT_V2_OPTION_ALERT_INSTANCES) {
1789 + if(ctl.options & (CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES | CONTEXT_V2_OPTION_ALERTS_WITH_VALUES)) {
1790 ctl.alerts.alert_instances = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1174 - NULL, sizeof(struct alert_instance_v2_entry));
1791 + NULL, sizeof(struct sql_alert_instance_v2_entry));
1792
1793 dictionary_register_insert_callback(ctl.alerts.alert_instances, alert_instances_v2_insert_callback, &ctl);
1794 dictionary_register_conflict_callback(ctl.alerts.alert_instances, alert_instances_v2_conflict_callback, &ctl);
1795 dictionary_register_delete_callback(ctl.alerts.alert_instances, alert_instances_delete_callback, &ctl);
1796 }
1180 -
1181 - if(ctl.options & CONTEXT_V2_OPTION_ALERT_CONFIGURATIONS) {
1182 - ctl.alerts.alert_configs = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1183 - NULL, sizeof(struct alert_config_v2_entry));
1184 -
1185 - dictionary_register_insert_callback(ctl.alerts.alert_configs, alert_configs_v2_insert_callback, &ctl);
1186 - dictionary_register_conflict_callback(ctl.alerts.alert_configs, alert_configs_v2_conflict_callback, &ctl);
1187 - dictionary_register_delete_callback(ctl.alerts.alert_configs, alert_configs_delete_callback, &ctl);
1188 - }
1797 }
1798
1799 if(req->after || req->before) {
1800 ctl.window.relative = rrdr_relative_window_to_absolute(&ctl.window.after, &ctl.window.before, &ctl.now);
1193 - ctl.window.enabled = true;
1801 + ctl.window.enabled = !(mode & CONTEXTS_V2_ALERT_TRANSITIONS);
1802 }
1803 else
1804 ctl.now = now_realtime_sec();
@@ -1221,16 +1829,24 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
1829 if (mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS))
1830 buffer_json_member_add_string(wb, "contexts", req->contexts);
1831
1224 - if(mode & CONTEXTS_V2_ALERTS) {
1832 + if(mode & (CONTEXTS_V2_ALERTS | CONTEXTS_V2_ALERT_TRANSITIONS)) {
1833 buffer_json_member_add_object(wb, "alerts");
1226 - web_client_api_request_v2_contexts_alerts_status_to_buffer_json_array(wb, "status", req->alerts.status);
1834 +
1835 + if(mode & CONTEXTS_V2_ALERTS)
1836 + web_client_api_request_v2_contexts_alerts_status_to_buffer_json_array(wb, "status", req->alerts.status);
1837 +
1838 + if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
1839 + buffer_json_member_add_string(wb, "context", req->contexts);
1840 + buffer_json_member_add_uint64(wb, "anchor_gi", req->alerts.global_id_anchor);
1841 + buffer_json_member_add_uint64(wb, "last", req->alerts.last);
1842 + }
1843 +
1844 buffer_json_member_add_string(wb, "alert", req->alerts.alert);
1845 buffer_json_member_add_string(wb, "transition", req->alerts.transition);
1229 - buffer_json_member_add_uint64(wb, "last", req->alerts.last);
1846 buffer_json_object_close(wb); // alerts
1847 }
1848 }
1233 - buffer_json_object_close(wb);
1849 + buffer_json_object_close(wb); // selectors
1850
1851 buffer_json_member_add_object(wb, "filters");
1852 {
@@ -1240,7 +1856,17 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
1856 buffer_json_member_add_time_t(wb, "after", req->after);
1857 buffer_json_member_add_time_t(wb, "before", req->before);
1858 }
1243 - buffer_json_object_close(wb);
1859 + buffer_json_object_close(wb); // filters
1860 +
1861 + if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
1862 + buffer_json_member_add_object(wb, "facets");
1863 + {
1864 + for (int i = 0; i < ATF_TOTAL_ENTRIES; i++) {
1865 + buffer_json_member_add_string(wb, alert_transition_facets[i].query_param, req->alerts.facets[i]);
1866 + }
1867 + }
1868 + buffer_json_object_close(wb); // facets
1869 + }
1870 }
1871 buffer_json_object_close(wb);
1872 }
@@ -1267,263 +1893,82 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
1893
1894 ctl.timings.executed_ut = now_monotonic_usec();
1895
1270 - if(mode & CONTEXTS_V2_NODES) {
1271 - buffer_json_member_add_array(wb, "nodes");
1272 - struct contexts_v2_node *t;
1273 - dfe_start_read(ctl.nodes.dict, t) {
1274 - rrdcontext_to_json_v2_rrdhost(wb, t->host, &ctl, t->ni);
1275 - }
1276 - dfe_done(t);
1277 - buffer_json_array_close(wb);
1896 + if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
1897 + contexts_v2_alert_transitions_to_json(wb, &ctl, debug);
1898 }
1279 -
1280 - if(mode & CONTEXTS_V2_FUNCTIONS) {
1281 - buffer_json_member_add_array(wb, "functions");
1282 - {
1283 - struct function_v2_entry *t;
1284 - dfe_start_read(ctl.functions.dict, t) {
1285 - buffer_json_add_array_item_object(wb);
1286 - buffer_json_member_add_string(wb, "name", t_dfe.name);
1287 - buffer_json_member_add_string(wb, "help", string2str(t->help));
1288 - buffer_json_member_add_array(wb, "ni");
1289 - for(size_t i = 0; i < t->used ;i++)
1290 - buffer_json_add_array_item_uint64(wb, t->node_ids[i]);
1291 - buffer_json_array_close(wb);
1292 - buffer_json_object_close(wb);
1899 + else {
1900 + if (mode & CONTEXTS_V2_NODES) {
1901 + buffer_json_member_add_array(wb, "nodes");
1902 + struct contexts_v2_node *t;
1903 + dfe_start_read(ctl.nodes.dict, t) {
1904 + rrdcontext_to_json_v2_rrdhost(wb, t->host, &ctl, t->ni);
1905 }
1906 dfe_done(t);
1907 + buffer_json_array_close(wb);
1908 }
1296 - buffer_json_array_close(wb);
1297 - }
1298 -
1299 - if(mode & CONTEXTS_V2_CONTEXTS) {
1300 - buffer_json_member_add_object(wb, "contexts");
1301 - {
1302 - struct context_v2_entry *z;
1303 - dfe_start_read(ctl.contexts.dict, z) {
1304 - bool collected = z->flags & RRD_FLAG_COLLECTED;
1305 -
1306 - buffer_json_member_add_object(wb, string2str(z->id));
1307 - {
1308 - buffer_json_member_add_string(wb, "family", string2str(z->family));
1309 - buffer_json_member_add_uint64(wb, "priority", z->priority);
1310 - buffer_json_member_add_time_t(wb, "first_entry", z->first_time_s);
1311 - buffer_json_member_add_time_t(wb, "last_entry", collected ? ctl.now : z->last_time_s);
1312 - buffer_json_member_add_boolean(wb, "live", collected);
1313 - if (mode & CONTEXTS_V2_SEARCH)
1314 - buffer_json_member_add_string(wb, "match", fts_match_to_string(z->match));
1315 - }
1316 - buffer_json_object_close(wb);
1317 - }
1318 - dfe_done(z);
1319 - }
1320 - buffer_json_object_close(wb); // contexts
1321 - }
1909
1323 - if(mode & CONTEXTS_V2_ALERTS) {
1324 - buffer_json_member_add_array(wb, "alerts");
1325 - {
1326 - struct alert_v2_entry *t;
1327 - dfe_start_read(ctl.alerts.alerts, t){
1328 - buffer_json_add_array_item_object(wb);
1329 - {
1330 - buffer_json_member_add_uint64(wb, "ati", t->ati);
1331 - buffer_json_member_add_string(wb, "nm", string2str(t->name));
1332 -
1333 - buffer_json_member_add_uint64(wb, "cr", t->critical);
1334 - buffer_json_member_add_uint64(wb, "wr", t->warning);
1335 - buffer_json_member_add_uint64(wb, "cl", t->clear);
1336 - buffer_json_member_add_uint64(wb, "er", t->error);
1337 -
1338 - buffer_json_member_add_uint64(wb, "in", t->instances);
1339 - buffer_json_member_add_uint64(wb, "nd", dictionary_entries(t->nodes));
1340 - buffer_json_member_add_uint64(wb, "cfg", dictionary_entries(t->configs));
1341 - }
1342 - buffer_json_object_close(wb); // alert name
1343 - }
1344 - dfe_done(t);
1345 - }
1346 - buffer_json_array_close(wb); // alerts
1347 -
1348 - if(req->options & CONTEXT_V2_OPTION_ALERT_INSTANCES) {
1349 - buffer_json_member_add_array(wb, "alert_instances");
1910 + if (mode & CONTEXTS_V2_FUNCTIONS) {
1911 + buffer_json_member_add_array(wb, "functions");
1912 {
1351 - struct alert_instance_v2_entry *t;
1352 - dfe_start_read(ctl.alerts.alert_instances, t){
1913 + struct function_v2_entry *t;
1914 + dfe_start_read(ctl.functions.dict, t) {
1915 buffer_json_add_array_item_object(wb);
1354 - {
1355 - buffer_json_member_add_uint64(wb, "ni", t->ni);
1356 - buffer_json_member_add_uint64(wb, "ati", t->ati);
1357 - buffer_json_member_add_uint64(wb, "aii", t->aii);
1358 - if(req->options & CONTEXT_V2_OPTION_ALERT_CONFIGURATIONS) {
1359 - buffer_json_member_add_uint64(wb, "aci", t->aci);
1360 - }
1361 - buffer_json_member_add_uint64(wb, "gi", t->global_id);
1362 -
1363 - if(debug)
1364 - buffer_json_member_add_string(wb, "nm", string2str(t->name));
1365 -
1366 - buffer_json_member_add_string(wb, "fami", string2str(t->family));
1367 - buffer_json_member_add_string(wb, "info", string2str(t->info));
1368 - buffer_json_member_add_string(wb, "ch", string2str(t->chart_name));
1369 - buffer_json_member_add_string(wb, "st", rrdcalc_status2string(t->status));
1370 - buffer_json_member_add_double(wb, "v", t->value);
1371 - buffer_json_member_add_time_t(wb, "t", t->last_updated);
1372 - buffer_json_member_add_uuid (wb, "tr_i", &t->last_transition_id);
1373 - buffer_json_member_add_double(wb, "tr_v", t->last_status_change_value);
1374 - buffer_json_member_add_time_t(wb, "tr_t", t->last_status_change);
1375 - buffer_json_member_add_uuid (wb, "cfg", &t->config_hash_id);
1376 - rrdcalc_flags_to_json_array (wb, "flags", t->flags);
1377 - }
1378 - buffer_json_object_close(wb); // alert instance
1916 + buffer_json_member_add_string(wb, "name", t_dfe.name);
1917 + buffer_json_member_add_string(wb, "help", string2str(t->help));
1918 + buffer_json_member_add_array(wb, "ni");
1919 + for (size_t i = 0; i < t->used; i++)
1920 + buffer_json_add_array_item_uint64(wb, t->node_ids[i]);
1921 + buffer_json_array_close(wb);
1922 + buffer_json_object_close(wb);
1923 }
1924 dfe_done(t);
1925 }
1382 - buffer_json_array_close(wb); // alerts_instances
1383 -
1384 - if(req->options & CONTEXT_V2_OPTION_ALERT_TRANSITIONS) {
1385 - buffer_json_member_add_array(wb, "alert_transitions");
1386 - sql_health_alarm_log2json_v3(
1387 - wb,
1388 - ctl.alerts.alert_instances,
1389 - ctl.request->after,
1390 - ctl.request->before,
1391 - ctl.request->alerts.transition,
1392 - ctl.request->alerts.last ? ctl.request->alerts.last : 1,
1393 - debug);
1394 - buffer_json_array_close(wb); // alerts_transitions
1395 - }
1926 + buffer_json_array_close(wb);
1927 }
1928
1398 - if(req->options & CONTEXT_V2_OPTION_ALERT_CONFIGURATIONS) {
1399 - buffer_json_member_add_array(wb, "alert_configurations");
1929 + if (mode & CONTEXTS_V2_CONTEXTS) {
1930 + buffer_json_member_add_object(wb, "contexts");
1931 {
1401 - struct alert_config_v2_entry *t;
1402 - dfe_start_read(ctl.alerts.alert_configs, t){
1403 - RRDCALC *rc = t->tmp;
1932 + struct context_v2_entry *z;
1933 + dfe_start_read(ctl.contexts.dict, z) {
1934 + bool collected = z->flags & RRD_FLAG_COLLECTED;
1935
1405 - buffer_json_add_array_item_object(wb);
1936 + buffer_json_member_add_object(wb, string2str(z->id));
1937 {
1407 - buffer_json_member_add_uint64(wb, "ati", t->ati);
1408 - buffer_json_member_add_uint64(wb, "aci", t->aci);
1409 - buffer_json_member_add_string(wb, "cfg", t_dfe.name);
1410 -
1411 - if(debug)
1412 - buffer_json_member_add_string(wb, "nm", string2str(rc->name));
1413 -
1414 - buffer_json_member_add_string(wb, "ctx", string2str(rc->rrdset->context));
1415 - buffer_json_member_add_string(wb, "class", string2str(rc->classification));
1416 - buffer_json_member_add_string(wb, "component", string2str(rc->component));
1417 - buffer_json_member_add_string(wb, "type", string2str(rc->type));
1418 - buffer_json_member_add_string(wb, "info", string2str(rc->original_info));
1419 -
1420 - buffer_json_member_add_object(wb, "v"); // value
1421 - {
1422 - buffer_json_member_add_uint64(wb, "update_every", rc->update_every);
1423 - buffer_json_member_add_string(wb, "units", string2str(rc->units));
1424 -
1425 - if (RRDCALC_HAS_DB_LOOKUP(rc) || debug) {
1426 - buffer_json_member_add_object(wb, "db");
1427 - {
1428 - if (rc->dimensions || debug)
1429 - buffer_json_member_add_string(wb, "dimensions", rrdcalc_dimensions(rc));
1430 -
1431 - buffer_json_member_add_string(wb, "method", time_grouping_method2string(rc->group));
1432 - buffer_json_member_add_time_t(wb, "after", rc->after);
1433 - buffer_json_member_add_time_t(wb, "before", rc->before);
1434 -
1435 - web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", (RRDR_OPTIONS) rc->options);
1436 - }
1437 - buffer_json_object_close(wb); // db
1438 - }
1439 -
1440 - if (rc->calculation || debug) {
1441 - buffer_json_member_add_string(wb, "calc", rc->calculation ? rc->calculation->source : NULL);
1442 - // buffer_json_member_add_string(wb, "calc_parsed", rc->calculation->parsed_as);
1443 - }
1444 - }
1445 - buffer_json_object_close(wb); // value
1446 -
1447 - if(rc->warning || rc->critical || debug) {
1448 - buffer_json_member_add_object(wb, "st"); // conditions
1449 - {
1450 - if(!isnan(rc->green) || debug)
1451 - buffer_json_member_add_double(wb, "green", rc->green);
1452 -
1453 - if(!isnan(rc->red) || debug)
1454 - buffer_json_member_add_double(wb, "red", rc->red);
1455 -
1456 - if (rc->warning || debug) {
1457 - buffer_json_member_add_string(wb, "warn", rc->warning ? rc->warning->source : NULL);
1458 - // buffer_json_member_add_string(wb, "warn_parsed", rc->warning ? rc->warning->parsed_as : NULL);
1459 - }
1460 -
1461 - if (rc->critical || debug) {
1462 - buffer_json_member_add_string(wb, "crit", rc->critical ? rc->critical->source : NULL);
1463 - // buffer_json_member_add_string(wb, "crit_parsed", rc->critical ? rc->critical->parsed_as : NULL);
1464 - }
1465 - }
1466 - buffer_json_object_close(wb); // conditions
1467 - }
1468 -
1469 - buffer_json_member_add_object(wb, "nf");
1470 - {
1471 - buffer_json_member_add_string(wb, "type", "agent");
1472 - buffer_json_member_add_string(wb, "method", rc->exec ? rrdcalc_exec(rc) : string2str(localhost->health.health_default_exec));
1473 - buffer_json_member_add_string(wb, "to", rc->recipient ? string2str(rc->recipient) : string2str(rc->rrdset->rrdhost->health.health_default_recipient));
1474 -
1475 - if(rc->delay_up_duration || rc->delay_down_duration || debug) {
1476 - buffer_json_member_add_object(wb, "delay");
1477 - {
1478 - buffer_json_member_add_time_t(wb, "up", rc->delay_up_duration);
1479 - buffer_json_member_add_time_t(wb, "down", rc->delay_down_duration);
1480 - buffer_json_member_add_time_t(wb, "max", rc->delay_max_duration);
1481 - buffer_json_member_add_double(wb, "multiplier", rc->delay_multiplier);
1482 - }
1483 - buffer_json_object_close(wb); //delay
1484 - }
1485 -
1486 - if(rc->warn_repeat_every || rc->crit_repeat_every || debug) {
1487 - buffer_json_member_add_object(wb, "repeat");
1488 - {
1489 - if(rc->warn_repeat_every || debug)
1490 - buffer_json_member_add_time_t(wb, "warn", rc->warn_repeat_every);
1491 -
1492 - if(rc->crit_repeat_every || debug)
1493 - buffer_json_member_add_time_t(wb, "crit", rc->crit_repeat_every);
1494 - }
1495 - buffer_json_object_close(wb); // repeat
1496 - }
1497 -
1498 - if (unlikely((rc->options & RRDCALC_OPTION_NO_CLEAR_NOTIFICATION) || debug))
1499 - buffer_json_member_add_boolean(wb, "no_clear_notification", rc->options & RRDCALC_OPTION_NO_CLEAR_NOTIFICATION);
1500 - }
1501 - buffer_json_object_close(wb); // notification
1502 - buffer_json_member_add_string(wb, "src", string2str(rc->source));
1938 + buffer_json_member_add_string(wb, "family", string2str(z->family));
1939 + buffer_json_member_add_uint64(wb, "priority", z->priority);
1940 + buffer_json_member_add_time_t(wb, "first_entry", z->first_time_s);
1941 + buffer_json_member_add_time_t(wb, "last_entry", collected ? ctl.now : z->last_time_s);
1942 + buffer_json_member_add_boolean(wb, "live", collected);
1943 + if (mode & CONTEXTS_V2_SEARCH)
1944 + buffer_json_member_add_string(wb, "match", fts_match_to_string(z->match));
1945 }
1504 - buffer_json_object_close(wb); // alert config
1946 + buffer_json_object_close(wb);
1947 }
1506 - dfe_done(t);
1948 + dfe_done(z);
1949 }
1508 - buffer_json_array_close(wb); // alerts_configs
1950 + buffer_json_object_close(wb); // contexts
1951 }
1510 - }
1952
1512 - if(mode & CONTEXTS_V2_SEARCH) {
1513 - buffer_json_member_add_object(wb, "searches");
1514 - {
1515 - buffer_json_member_add_uint64(wb, "strings", ctl.q.fts.string_searches);
1516 - buffer_json_member_add_uint64(wb, "char", ctl.q.fts.char_searches);
1517 - buffer_json_member_add_uint64(wb, "total", ctl.q.fts.searches);
1953 + if (mode & CONTEXTS_V2_ALERTS)
1954 + contexts_v2_alerts_to_json(wb, &ctl, debug);
1955 +
1956 + if (mode & CONTEXTS_V2_SEARCH) {
1957 + buffer_json_member_add_object(wb, "searches");
1958 + {
1959 + buffer_json_member_add_uint64(wb, "strings", ctl.q.fts.string_searches);
1960 + buffer_json_member_add_uint64(wb, "char", ctl.q.fts.char_searches);
1961 + buffer_json_member_add_uint64(wb, "total", ctl.q.fts.searches);
1962 + }
1963 + buffer_json_object_close(wb);
1964 }
1519 - buffer_json_object_close(wb);
1520 - }
1965
1522 - if(mode & (CONTEXTS_V2_VERSIONS))
1523 - version_hashes_api_v2(wb, &ctl.versions);
1966 + if (mode & (CONTEXTS_V2_VERSIONS))
1967 + version_hashes_api_v2(wb, &ctl.versions);
1968
1525 - if(mode & CONTEXTS_V2_AGENTS)
1526 - buffer_json_agents_array_v2(wb, &ctl.timings, ctl.now, mode & (CONTEXTS_V2_AGENTS_INFO));
1969 + if (mode & CONTEXTS_V2_AGENTS)
1970 + buffer_json_agents_array_v2(wb, &ctl.timings, ctl.now, mode & (CONTEXTS_V2_AGENTS_INFO));
1971 + }
1972
1973 buffer_json_cloud_timings(wb, "timings", &ctl.timings);
1974
@@ -1535,7 +1980,6 @@ cleanup:
1980 dictionary_destroy(ctl.functions.dict);
1981 dictionary_destroy(ctl.alerts.alerts);
1982 dictionary_destroy(ctl.alerts.alert_instances);
1538 - dictionary_destroy(ctl.alerts.alert_configs);
1983 simple_pattern_free(ctl.nodes.scope_pattern);
1984 simple_pattern_free(ctl.nodes.pattern);
1985 simple_pattern_free(ctl.contexts.pattern);
database/contexts/rrdcontext.h
+138 -13
@@ -415,17 +415,117 @@ typedef struct query_target {
415 } internal;
416 } QUERY_TARGET;
417
418 -struct alert_instance_v2_entry {
418 +
419 +struct sql_alert_transition_data {
420 + usec_t global_id;
421 + uuid_t *transition_id;
422 + uuid_t *host_id;
423 + uuid_t *config_hash_id;
424 + uint32_t alarm_id;
425 + const char *alert_name;
426 + const char *chart;
427 + const char *chart_context;
428 + const char *family;
429 + const char *recipient;
430 + const char *units;
431 + const char *exec;
432 + const char *info;
433 + const char *classification;
434 + const char *type;
435 + const char *component;
436 + time_t when_key;
437 + time_t duration;
438 + time_t non_clear_duration;
439 + uint64_t flags;
440 + time_t delay_up_to_timestamp;
441 + time_t exec_run_timestamp;
442 + int exec_code;
443 + int new_status;
444 + int old_status;
445 + int delay;
446 + time_t last_repeat;
447 + NETDATA_DOUBLE new_value;
448 + NETDATA_DOUBLE old_value;
449 +
450 + char machine_guid[UUID_STR_LEN];
451 + struct sql_alert_transition_data *next;
452 + struct sql_alert_transition_data *prev;
453 +};
454 +
455 +struct sql_alert_config_data {
456 + uuid_t *config_hash_id;
457 + const char *name;
458 +
459 + struct {
460 + const char *on_template;
461 + const char *on_key;
462 +
463 + const char *os;
464 + const char *hosts;
465 + const char *families;
466 + const char *plugin;
467 + const char *module;
468 + const char *host_labels;
469 + const char *chart_labels;
470 + const char *charts;
471 + } selectors;
472 +
473 + const char *info;
474 + const char *classification;
475 + const char *component;
476 + const char *type;
477 +
478 + struct {
479 + struct {
480 + const char *dimensions;
481 + const char *method;
482 + uint32_t options;
483 +
484 + int32_t after;
485 + int32_t before;
486 +
487 + const char *lookup; // the lookup line, unparsed
488 + } db;
489 +
490 + const char *calc; // the calculation expression, unparsed
491 + const char *units;
492 +
493 + int32_t update_every; // the update frequency of the alert, in seconds
494 + const char *every; // the every line, unparsed
495 + } value;
496 +
497 + struct {
498 + const char *green; // the green threshold, unparsed
499 + const char *red; // the red threshold, unparsed
500 + const char *warn; // the warning expression, unparsed
501 + const char *crit; // the critical expression, unparsed
502 + } status;
503 +
504 + struct {
505 + const char *exec; // the script to execute, or NULL to execute the default script
506 + const char *to_key; // the recipient, or NULL for the default recipient
507 + const char *delay; // the delay line, unparsed
508 + const char *repeat; // the repeat line, unparsed
509 + const char *options; // FIXME what is this?
510 + } notification;
511 +
512 + const char *source; // the configuration file and line this alert came from
513 +};
514 +
515 +int contexts_v2_alert_config_to_json(struct web_client *w, const char *config_hash_id);
516 +
517 +struct sql_alert_instance_v2_entry {
518 RRDCALC *tmp;
519
520 size_t ati;
422 - size_t aci;
423 - size_t aii;
521
522 + STRING *context;
523 STRING *chart_id;
524 STRING *chart_name;
525 STRING *name;
526 STRING *family;
527 + STRING *units;
528 + STRING *source;
529 RRDCALC_STATUS status;
530 RRDCALC_FLAGS flags;
531 STRING *info;
@@ -486,6 +586,27 @@ void query_target_release(QUERY_TARGET *qt);
586
587 QUERY_TARGET *query_target_create(QUERY_TARGET_REQUEST *qtr);
588
589 +typedef enum __attribute__((packed)) {
590 + ATF_STATUS = 0,
591 + ATF_CLASS,
592 + ATF_TYPE,
593 + ATF_COMPONENT,
594 + ATF_ROLE,
595 + ATF_NODE,
596 +
597 + // total
598 + ATF_TOTAL_ENTRIES,
599 +} ALERT_TRANSITION_FACET;
600 +
601 +struct alert_transitions_facets {
602 + const char *name;
603 + const char *query_param;
604 + const char *id;
605 + size_t order;
606 +};
607 +
608 +extern struct alert_transitions_facets alert_transition_facets[];
609 +
610 struct api_v2_contexts_request {
611 char *scope_nodes;
612 char *scope_contexts;
@@ -500,6 +621,9 @@ struct api_v2_contexts_request {
621 char *alert;
622 char *transition;
623 uint32_t last;
624 +
625 + const char *facets[ATF_TOTAL_ENTRIES];
626 + usec_t global_id_anchor;
627 } alerts;
628
629 time_t after;
@@ -511,16 +635,17 @@ struct api_v2_contexts_request {
635 };
636
637 typedef enum __attribute__ ((__packed__)) {
514 - CONTEXTS_V2_SEARCH = (1 << 1),
515 - CONTEXTS_V2_NODES = (1 << 2),
516 - CONTEXTS_V2_NODES_INFO = (1 << 3),
517 - CONTEXTS_V2_NODES_INSTANCES = (1 << 4),
518 - CONTEXTS_V2_CONTEXTS = (1 << 5),
519 - CONTEXTS_V2_AGENTS = (1 << 6),
520 - CONTEXTS_V2_AGENTS_INFO = (1 << 7),
521 - CONTEXTS_V2_VERSIONS = (1 << 8),
522 - CONTEXTS_V2_FUNCTIONS = (1 << 9),
523 - CONTEXTS_V2_ALERTS = (1 << 10),
638 + CONTEXTS_V2_SEARCH = (1 << 1),
639 + CONTEXTS_V2_NODES = (1 << 2),
640 + CONTEXTS_V2_NODES_INFO = (1 << 3),
641 + CONTEXTS_V2_NODE_INSTANCES = (1 << 4),
642 + CONTEXTS_V2_CONTEXTS = (1 << 5),
643 + CONTEXTS_V2_AGENTS = (1 << 6),
644 + CONTEXTS_V2_AGENTS_INFO = (1 << 7),
645 + CONTEXTS_V2_VERSIONS = (1 << 8),
646 + CONTEXTS_V2_FUNCTIONS = (1 << 9),
647 + CONTEXTS_V2_ALERTS = (1 << 10),
648 + CONTEXTS_V2_ALERT_TRANSITIONS = (1 << 11),
649 } CONTEXTS_V2_MODE;
650
651 int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTEXTS_V2_MODE mode);
database/engine/journalfile.c
+8 -1
@@ -651,7 +651,7 @@ static int journalfile_check_superblock(uv_file file)
651
652 static void journalfile_restore_extent_metadata(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile, void *buf, unsigned max_size)
653 {
654 - static BITMAP256 page_error_map;
654 + static BITMAP256 page_error_map = BITMAP256_INITIALIZER;
655 unsigned i, count, payload_length, descr_size;
656 struct rrdeng_jf_store_data *jf_metric_data;
657
@@ -998,6 +998,7 @@ void journalfile_v2_populate_retention_to_mrg(struct rrdengine_instance *ctx, st
998
999 struct journal_metric_list *metric = (struct journal_metric_list *) (data_start + j2_header->metric_offset);
1000 time_t header_start_time_s = (time_t) (j2_header->start_time_ut / USEC_PER_SEC);
1001 + time_t global_first_time_s = header_start_time_s;
1002 time_t now_s = max_acceptable_collected_time();
1003 for (size_t i=0; i < entries; i++) {
1004 time_t start_time_s = header_start_time_s + metric->delta_start_s;
@@ -1018,6 +1019,12 @@ void journalfile_v2_populate_retention_to_mrg(struct rrdengine_instance *ctx, st
1019 , (double)entries / 1000
1020 , ((double)(ended_ut - started_ut) / USEC_PER_MS)
1021 );
1022 +
1023 + time_t old = __atomic_load_n(&ctx->atomic.first_time_s, __ATOMIC_RELAXED);;
1024 + do {
1025 + if(old <= global_first_time_s)
1026 + break;
1027 + } while(!__atomic_compare_exchange_n(&ctx->atomic.first_time_s, &old, global_first_time_s, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED));
1028 }
1029
1030 int journalfile_v2_load(struct rrdengine_instance *ctx, struct rrdengine_journalfile *journalfile, struct rrdengine_datafile *datafile)
database/engine/rrdengine.c
+16 -3
@@ -998,12 +998,14 @@ struct rrdengine_datafile *datafile_release_and_acquire_next_for_retention(struc
998 return next_datafile;
999 }
1000
1001 -void find_uuid_first_time(
1001 +time_t find_uuid_first_time(
1002 struct rrdengine_instance *ctx,
1003 struct rrdengine_datafile *datafile,
1004 struct uuid_first_time_s *uuid_first_entry_list,
1005 size_t count)
1006 {
1007 + time_t global_first_time_s = LONG_MAX;
1008 +
1009 // acquire the datafile to work with it
1010 uv_rwlock_rdlock(&ctx->datafiles.rwlock);
1011 while(datafile && !datafile_acquire(datafile, DATAFILE_ACQUIRE_RETENTION))
@@ -1011,7 +1013,7 @@ void find_uuid_first_time(
1013 uv_rwlock_rdunlock(&ctx->datafiles.rwlock);
1014
1015 if (unlikely(!datafile))
1014 - return;
1016 + return global_first_time_s;
1017
1018 unsigned journalfile_count = 0;
1019 size_t binary_match = 0;
@@ -1025,6 +1027,10 @@ void find_uuid_first_time(
1027 }
1028
1029 time_t journal_start_time_s = (time_t) (j2_header->start_time_ut / USEC_PER_SEC);
1030 +
1031 + if(journal_start_time_s < global_first_time_s)
1032 + global_first_time_s = journal_start_time_s;
1033 +
1034 struct journal_metric_list *uuid_list = (struct journal_metric_list *)((uint8_t *) j2_header + j2_header->metric_offset);
1035 struct uuid_first_time_s *uuid_original_entry;
1036
@@ -1137,9 +1143,13 @@ void find_uuid_first_time(
1143 without_retention,
1144 without_metric
1145 );
1146 +
1147 + return global_first_time_s;
1148 }
1149
1150 static void update_metrics_first_time_s(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile_to_delete, struct rrdengine_datafile *first_datafile_remaining, bool worker) {
1151 + time_t global_first_time_s = LONG_MAX;
1152 +
1153 if(worker)
1154 worker_is_busy(UV_EVENT_DBENGINE_FIND_ROTATED_METRICS);
1155
@@ -1184,7 +1194,7 @@ static void update_metrics_first_time_s(struct rrdengine_instance *ctx, struct r
1194 if(worker)
1195 worker_is_busy(UV_EVENT_DBENGINE_FIND_REMAINING_RETENTION);
1196
1187 - find_uuid_first_time(ctx, first_datafile_remaining, uuid_first_entry_list, added);
1197 + global_first_time_s = find_uuid_first_time(ctx, first_datafile_remaining, uuid_first_entry_list, added);
1198
1199 if(worker)
1200 worker_is_busy(UV_EVENT_DBENGINE_POPULATE_MRG);
@@ -1223,6 +1233,9 @@ static void update_metrics_first_time_s(struct rrdengine_instance *ctx, struct r
1233 "DBENGINE: deleted %zu metrics, zero retention but referenced %zu (out of %zu total, of which %zu have main cache retention) zero on-disk retention tier %d metrics from metrics registry",
1234 deleted_metrics, zero_retention_referenced, zero_disk_retention, zero_disk_but_live, ctx->config.tier);
1235
1236 + if(global_first_time_s != LONG_MAX)
1237 + __atomic_store_n(&ctx->atomic.first_time_s, global_first_time_s, __ATOMIC_RELAXED);
1238 +
1239 if(worker)
1240 worker_is_idle();
1241 }
database/engine/rrdengine.h
+2
@@ -383,6 +383,8 @@ struct rrdengine_instance {
383 bool migration_to_v2_running;
384 bool now_deleting_files;
385 unsigned extents_currently_being_flushed; // non-zero until we commit data to disk (both datafile and journal file)
386 +
387 + time_t first_time_s;
388 } atomic;
389
390 struct {
database/engine/rrdengineapi.c
+13
@@ -1012,6 +1012,16 @@ size_t rrdeng_disk_space_used(STORAGE_INSTANCE *db_instance) {
1012 return __atomic_load_n(&ctx->atomic.current_disk_space, __ATOMIC_RELAXED);
1013 }
1014
1015 +time_t rrdeng_global_first_time_s(STORAGE_INSTANCE *db_instance) {
1016 + struct rrdengine_instance *ctx = (struct rrdengine_instance *)db_instance;
1017 + return __atomic_load_n(&ctx->atomic.first_time_s, __ATOMIC_RELAXED);
1018 +}
1019 +
1020 +size_t rrdeng_currently_collected_metrics(STORAGE_INSTANCE *db_instance) {
1021 + struct rrdengine_instance *ctx = (struct rrdengine_instance *)db_instance;
1022 + return __atomic_load_n(&ctx->atomic.collectors_running, __ATOMIC_RELAXED);
1023 +}
1024 +
1025 /*
1026 * Gathers Database Engine statistics.
1027 * Careful when modifying this function.
@@ -1182,6 +1192,9 @@ int rrdeng_init(struct rrdengine_instance **ctxp, const char *dbfiles_path,
1192 ctx->atomic.transaction_id = 1;
1193 ctx->quiesce.enabled = false;
1194
1195 + rw_spinlock_init(&ctx->njfv2idx.spinlock);
1196 + ctx->atomic.first_time_s = LONG_MAX;
1197 +
1198 if (rrdeng_dbengine_spawn(ctx) && !init_rrd_files(ctx)) {
1199 // success - we run this ctx too
1200 rrdeng_populate_mrg(ctx);
database/rrd.h
+21
@@ -526,6 +526,27 @@ static inline size_t storage_engine_disk_space_used(STORAGE_ENGINE_BACKEND backe
526 return 0;
527 }
528
529 +time_t rrdeng_global_first_time_s(STORAGE_INSTANCE *db_instance);
530 +static inline time_t storage_engine_global_first_time_s(STORAGE_ENGINE_BACKEND backend __maybe_unused, STORAGE_INSTANCE *db_instance) {
531 +#ifdef ENABLE_DBENGINE
532 + if(likely(backend == STORAGE_ENGINE_BACKEND_DBENGINE))
533 + return rrdeng_global_first_time_s(db_instance);
534 +#endif
535 +
536 + return now_realtime_sec() - (time_t)(default_rrd_history_entries * default_rrd_update_every);
537 +}
538 +
539 +size_t rrdeng_currently_collected_metrics(STORAGE_INSTANCE *db_instance);
540 +static inline size_t storage_engine_collected_metrics(STORAGE_ENGINE_BACKEND backend __maybe_unused, STORAGE_INSTANCE *db_instance) {
541 +#ifdef ENABLE_DBENGINE
542 + if(likely(backend == STORAGE_ENGINE_BACKEND_DBENGINE))
543 + return rrdeng_currently_collected_metrics(db_instance);
544 +#endif
545 +
546 + // TODO - calculate the total host disk space for memory mode save and map
547 + return 0;
548 +}
549 +
550 void rrdeng_store_metric_flush_current_page(STORAGE_COLLECT_HANDLE *collection_handle);
551 void rrddim_store_metric_flush(STORAGE_COLLECT_HANDLE *collection_handle);
552 static inline void storage_engine_store_flush(STORAGE_COLLECT_HANDLE *collection_handle) {
database/rrdhost.c
+4 -4
@@ -1117,8 +1117,8 @@ static void rrdhost_streaming_sender_structures_init(RRDHOST *host)
1117 host->sender->rrdpush_sender_pipe[PIPE_WRITE] = -1;
1118 host->sender->rrdpush_sender_socket = -1;
1119
1120 -#ifdef ENABLE_COMPRESSION
1121 - if(default_compression_enabled)
1120 +#ifdef ENABLE_RRDPUSH_COMPRESSION
1121 + if(default_rrdpush_compression_enabled)
1122 host->sender->flags |= SENDER_FLAG_COMPRESSION;
1123 else
1124 host->sender->flags &= ~SENDER_FLAG_COMPRESSION;
@@ -1137,7 +1137,7 @@ static void rrdhost_streaming_sender_structures_free(RRDHOST *host)
1137
1138 rrdpush_sender_thread_stop(host, STREAM_HANDSHAKE_DISCONNECT_HOST_CLEANUP, true); // stop a possibly running thread
1139 cbuffer_free(host->sender->buffer);
1140 -#ifdef ENABLE_COMPRESSION
1140 +#ifdef ENABLE_RRDPUSH_COMPRESSION
1141 rrdpush_compressor_destroy(&host->sender->compressor);
1142 #endif
1143 replication_cleanup_sender(host->sender);
@@ -1852,7 +1852,7 @@ void rrdhost_status(RRDHOST *host, time_t now, RRDHOST_STATUS *s) {
1852 else
1853 s->stream.status = RRDHOST_STREAM_STATUS_ONLINE;
1854
1855 -#ifdef ENABLE_COMPRESSION
1855 +#ifdef ENABLE_RRDPUSH_COMPRESSION
1856 s->stream.compression = (stream_has_capability(host->sender, STREAM_CAP_COMPRESSION) && host->sender->compressor.initialized);
1857 #endif
1858 }
database/sqlite/sqlite_health.c
+258 -124
@@ -1746,187 +1746,321 @@ fail:
1746 return ok;
1747 }
1748
1749 -#define SQL_BUILD_TEMP_ALERT_MATCH "CREATE TEMP TABLE IF NOT EXISTS v_%p (host_id blob, chart text, name text, alarm_id int, aii int, ati int, aci int)"
1750 -
1751 -#define SQL_POPULATE_TEMP_ALERT_MATCH_TABLE "INSERT INTO v_%p (host_id, chart, name, alarm_id, aii, ati, aci) " \
1752 - "VALUES (@host_id, @chart, @alarm_name, @alarm_id, @aii, @ati, @aci)"
1753 -
1754 -#define SQL_SEARCH_ALERT_LOG "SELECT when_key, duration, flags, exec_run_timestamp, delay_up_to_timestamp, " \
1755 - "recipient, exec_code, new_status, old_status, new_value, " \
1756 - "old_value, transition_id, d.global_id, t.aii, t.ati, t.aci, h.exec FROM health_log_detail d, health_log h, v_%p t " \
1757 - "WHERE h.host_id = t.host_id AND h.chart = t.chart AND h.alarm_id = t.alarm_id AND h.name = t.name " \
1758 - "AND h.health_log_id = d.health_log_id "
1759 -
1760 -void sql_health_alarm_log2json_v3(BUFFER *wb, DICTIONARY *alert_instances, time_t after, time_t before, const char *transition, uint32_t max, bool debug __maybe_unused)
1749 +#define SQL_BUILD_ALERT_TRANSITION "CREATE TEMP TABLE IF NOT EXISTS v_%p (host_id blob)"
1750 +
1751 +#define SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE "INSERT INTO v_%p (host_id) VALUES (@host_id)"
1752 +
1753 +#define SQL_SEARCH_ALERT_TRANSITION "SELECT h.host_id, h.alarm_id, h.config_hash_id, h.name, h.chart, h.family, h.recipient, h.units, h.exec, h.chart_context, d.when_key, " \
1754 + "d.duration, d.non_clear_duration, d.flags, d.delay_up_to_timestamp, d.info, d.exec_code, d.new_status, d.old_status, d.delay, " \
1755 + " d.new_value, d.old_value, d.last_repeat, d.transition_id, d.global_id, ah.class, ah.type, ah.component FROM health_log h, health_log_detail d, v_%p t, alert_hash ah " \
1756 + " WHERE h.host_id = t.host_id AND h.config_hash_id = ah.hash_id AND h.health_log_id = d.health_log_id AND d.global_id BETWEEN @after AND @before "
1757 +
1758 +
1759 +#define SQL_SEARCH_ALERT_TRANSITION_DIRECT "SELECT h.host_id, h.alarm_id, h.config_hash_id, h.name, h.chart, h.family, h.recipient, h.units, h.exec, h.chart_context, d.when_key, " \
1760 + "d.duration, d.non_clear_duration, d.flags, d.delay_up_to_timestamp, d.info, d.exec_code, d.new_status, d.old_status, d.delay, " \
1761 + " d.new_value, d.old_value, d.last_repeat, d.transition_id, d.global_id, ah.class, ah.type, ah.component, d.exec_run_timestamp FROM health_log h, health_log_detail d, alert_hash ah " \
1762 + " WHERE h.config_hash_id = ah.hash_id AND h.health_log_id = d.health_log_id AND transition_id = @transition "
1763 +
1764 +void sql_alert_transitions(
1765 + DICTIONARY *nodes,
1766 + time_t after,
1767 + time_t before,
1768 + const char *context,
1769 + const char *alert_name,
1770 + const char *transition,
1771 + void (*cb)(struct sql_alert_transition_data *, void *),
1772 + void *data,
1773 + bool debug __maybe_unused)
1774 {
1775 uuid_t transition_uuid;
1776 char sql[512];
1764 - sqlite3_stmt *res = NULL;
1777 int rc;
1778 + sqlite3_stmt *res = NULL;
1779 BUFFER *command = NULL;
1780
1768 - if (unlikely(!alert_instances))
1781 + if (unlikely(!nodes))
1782 return;
1783
1784 if (transition) {
1785 if (uuid_parse(transition, transition_uuid)) {
1773 - error_report("Invalid transition given %s", transition);
1774 - return;
1786 + error_report("Invalid transition given %s", transition);
1787 + return;
1788 + }
1789 +
1790 + rc = sqlite3_prepare_v2(db_meta, SQL_SEARCH_ALERT_TRANSITION_DIRECT, -1, &res, 0);
1791 +
1792 + rc = sqlite3_bind_blob(res, 1, &transition_uuid, sizeof(transition_uuid), SQLITE_STATIC);
1793 + if (unlikely(rc != SQLITE_OK)) {
1794 + error_report("Failed to bind transition_id parameter");
1795 + goto fail;
1796 }
1797 + goto run_query;
1798 }
1799
1778 - snprintfz(sql, 511, SQL_BUILD_TEMP_ALERT_MATCH, alert_instances);
1800 + snprintfz(sql, 511, SQL_BUILD_ALERT_TRANSITION, nodes);
1801 rc = db_execute(db_meta, sql);
1802 if (rc)
1803 return;
1804
1783 - snprintfz(sql, 511, SQL_POPULATE_TEMP_ALERT_MATCH_TABLE, alert_instances);
1805 + snprintfz(sql, 511, SQL_POPULATE_TEMP_ALERT_TRANSITION_TABLE, nodes);
1806
1807 // Prepare statement to add things
1808 rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
1809 if (unlikely(rc != SQLITE_OK)) {
1788 - error_report("Failed to prepare statement to INSERT into v_%p", alert_instances);
1810 + error_report("Failed to prepare statement to INSERT into v_%p", nodes);
1811 goto fail_only_drop;
1812 }
1813
1792 - struct alert_instance_v2_entry *t;
1793 - dfe_start_read(alert_instances, t) {
1794 - rc = sqlite3_bind_blob(res, 1, &t->host->host_uuid, sizeof(t->host->host_uuid), SQLITE_STATIC);
1795 - if (unlikely(rc != SQLITE_OK))
1796 - error_report("Failed to bind host_id parameter.");
1797 -
1798 - rc = sqlite3_bind_text(res, 2, string2str(t->chart_name), -1, SQLITE_STATIC);
1799 - if (unlikely(rc != SQLITE_OK))
1800 - error_report("Failed to bind chart_name parameter.");
1814 + void *t;
1815 + dfe_start_read(nodes, t) {
1816 + uuid_t host_uuid;
1817 + uuid_parse( t_dfe.name, host_uuid);
1818
1802 - rc = sqlite3_bind_text(res, 3, string2str(t->name), -1, SQLITE_STATIC);
1803 - if (unlikely(rc != SQLITE_OK))
1804 - error_report("Failed to bind alert_name parameter.");
1805 -
1806 - rc = sqlite3_bind_int(res, 4, (int) t->alarm_id);
1807 - if (unlikely(rc != SQLITE_OK))
1808 - error_report("Failed to bind alarm_id parameter.");
1809 -
1810 - rc = sqlite3_bind_int(res, 5, (int) t->aii);
1811 - if (unlikely(rc != SQLITE_OK))
1812 - error_report("Failed to bind aii parameter.");
1813 -
1814 - rc = sqlite3_bind_int(res, 6, (int) t->ati);
1815 - if (unlikely(rc != SQLITE_OK))
1816 - error_report("Failed to bind ati parameter.");
1817 -
1818 - rc = sqlite3_bind_int(res, 7, (int) t->aci);
1819 - if (unlikely(rc != SQLITE_OK))
1820 - error_report("Failed to bind aci parameter.");
1819 + rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC);
1820 + if (unlikely(rc != SQLITE_OK))
1821 + error_report("Failed to bind host_id parameter.");
1822
1822 - rc = sqlite3_step_monitored(res);
1823 - if (rc != SQLITE_DONE)
1824 - error_report("Error while populating temp table");
1823 + rc = sqlite3_step_monitored(res);
1824 + if (rc != SQLITE_DONE)
1825 + error_report("Error while populating temp table");
1826
1826 - rc = sqlite3_reset(res);
1827 - if (rc != SQLITE_OK)
1828 - error_report("Error while resetting parameters");
1827 + rc = sqlite3_reset(res);
1828 + if (rc != SQLITE_OK)
1829 + error_report("Error while resetting parameters");
1830 }
1831 dfe_done(t);
1832
1833 rc = sqlite3_finalize(res);
1834 if (unlikely(rc != SQLITE_OK)) {
1835 // log error but continue
1835 - error_report("Failed to finalize statement for sql_health_alarm_log2json_v3 temp table population");
1836 + error_report("Failed to finalize statement for sql_alert_transitions temp table population");
1837 }
1838
1839 command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
1840
1840 - buffer_sprintf(command, SQL_SEARCH_ALERT_LOG, alert_instances);
1841 -
1842 - if (transition)
1843 - buffer_sprintf(command, " AND d.global_id <= (SELECT global_id FROM health_log_detail WHERE transition_id = @transition) ");
1841 + buffer_sprintf(command, SQL_SEARCH_ALERT_TRANSITION, nodes);
1842
1845 - if (after)
1846 - buffer_sprintf(command, "AND d.when_key >= %ld ", after);
1843 + if (context)
1844 + buffer_sprintf(command, " AND h.chart_context = @context");
1845
1848 - if (before)
1849 - buffer_sprintf(command, "AND d.when_key < %ld ", before);
1850 -
1851 - buffer_sprintf(command, " ORDER BY d.global_id DESC LIMIT %u", max);
1846 + if (alert_name)
1847 + buffer_sprintf(command, " AND h.name = @alert_name");
1848
1849 rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0);
1850 if (unlikely(rc != SQLITE_OK)) {
1855 - error_report("Failed to prepare statement sql_health_alarm_log2json_v3");
1851 + error_report("Failed to prepare statement sql_alert_transitions");
1852 goto fail_only_drop;
1853 }
1854
1859 - if (transition) {
1860 - rc = sqlite3_bind_blob(res, 1, &transition_uuid, sizeof(transition_uuid), SQLITE_STATIC);
1855 + int param = 1;
1856 + rc = sqlite3_bind_int64(res, param++, (sqlite3_int64)(after * USEC_PER_SEC));
1857 + if (unlikely(rc != SQLITE_OK)) {
1858 + error_report("Failed to bind after parameter");
1859 + goto fail;
1860 + }
1861 +
1862 + rc = sqlite3_bind_int64(res, param++, (sqlite3_int64)(before * USEC_PER_SEC));
1863 + if (unlikely(rc != SQLITE_OK)) {
1864 + error_report("Failed to bind before parameter");
1865 + goto fail;
1866 + }
1867 +
1868 + if (context) {
1869 + rc = sqlite3_bind_text(res, param++, context, -1, SQLITE_STATIC);
1870 if (unlikely(rc != SQLITE_OK)) {
1862 - error_report("Failed to bind transition parameter");
1871 + error_report("Failed to bind context parameter");
1872 goto fail;
1873 }
1874 }
1875
1867 - while (sqlite3_step(res) == SQLITE_ROW) {
1868 - buffer_json_add_array_item_object(wb);
1869 - {
1870 - size_t aii = sqlite3_column_int64(res, 13);
1871 - size_t ati = sqlite3_column_int64(res, 14);
1872 - size_t aci = sqlite3_column_int64(res, 15);
1873 - buffer_json_member_add_uint64(wb, "aii", aii);
1874 - buffer_json_member_add_uint64(wb, "ati", ati);
1875 - buffer_json_member_add_uint64(wb, "aci", aci);
1876 -
1877 - uuid_t *transition_id = (sqlite3_column_type(res, 11) != SQLITE_NULL) ? ((uuid_t *)sqlite3_column_blob(res, 11)) : NULL;
1878 - buffer_json_member_add_uuid(wb, "tr_i", transition_id);
1879 -
1880 - buffer_json_member_add_uint64(wb, "gi", (uint64_t)sqlite3_column_int64(res, 12));
1881 -
1882 - uint64_t flags = sqlite3_column_int64(res, 2);
1883 - buffer_json_member_add_uint64(wb, "t", (long unsigned int)sqlite3_column_int64(res, 0));
1884 -
1885 - buffer_json_member_add_object(wb, "st");
1886 - {
1887 - buffer_json_member_add_string(wb, "new", rrdcalc_status2string(sqlite3_column_int(res, 7)));
1888 - buffer_json_member_add_string(wb, "old", rrdcalc_status2string(sqlite3_column_int(res, 8)));
1889 - buffer_json_member_add_uint64(wb, "dur", (long unsigned int)sqlite3_column_int64(res, 1)); // old duration
1890 - }
1891 - buffer_json_object_close(wb); //st
1892 - buffer_json_member_add_object(wb, "v");
1893 - {
1894 - NETDATA_DOUBLE n = (sqlite3_column_type(res, 9) == SQLITE_NULL) ? NAN : sqlite3_column_double(res, 9);
1895 - buffer_json_member_add_double(wb, "new", n);
1896 -
1897 - NETDATA_DOUBLE o = (sqlite3_column_type(res, 10) == SQLITE_NULL) ? NAN : sqlite3_column_double(res, 10);
1898 - buffer_json_member_add_double(wb, "old", o);
1899 - }
1900 - buffer_json_object_close(wb); // v
1901 -
1902 - buffer_json_member_add_object(wb, "nf");
1903 - {
1904 - const char *exec = (const char *)sqlite3_column_text(res, 16);
1905 - const char *recipient = (const char *)sqlite3_column_text(res, 5);
1906 -
1907 - buffer_json_member_add_string(wb, "type", "agent");
1908 - health_entry_flags_to_json_array(wb, "flags", flags);
1909 - buffer_json_member_add_uint64(wb, "t", (long unsigned int)sqlite3_column_int64(res, 9));
1910 - buffer_json_member_add_string(
1911 - wb, "method", exec ? (const char *)exec : string2str(localhost->health.health_default_exec));
1912 - buffer_json_member_add_string(
1913 - wb,
1914 - "to",
1915 - recipient ? recipient : string2str(localhost->health.health_default_recipient));
1916 - buffer_json_member_add_uint64(wb, "code", sqlite3_column_int(res, 6));
1917 - }
1918 - buffer_json_object_close(wb); // notification
1876 + if (alert_name) {
1877 + rc = sqlite3_bind_text(res, param++, alert_name, -1, SQLITE_STATIC);
1878 + if (unlikely(rc != SQLITE_OK)) {
1879 + error_report("Failed to bind alert_name parameter");
1880 + goto fail;
1881 }
1920 - buffer_json_object_close(wb);
1882 + }
1883 +
1884 +run_query:;
1885 +
1886 + struct sql_alert_transition_data atd = {0 };
1887 +
1888 + while (sqlite3_step(res) == SQLITE_ROW) {
1889 + atd.host_id = (uuid_t *) sqlite3_column_blob(res, 0);
1890 + atd.alarm_id = sqlite3_column_int64(res, 1);
1891 + atd.config_hash_id = (uuid_t *)sqlite3_column_blob(res, 2);
1892 + atd.alert_name = (const char *) sqlite3_column_text(res, 3);
1893 + atd.chart = (const char *) sqlite3_column_text(res, 4);
1894 + atd.family = (const char *) sqlite3_column_text(res, 5);
1895 + atd.recipient = (const char *) sqlite3_column_text(res, 6);
1896 + atd.units = (const char *) sqlite3_column_text(res, 7);
1897 + atd.exec = (const char *) sqlite3_column_text(res, 8);
1898 + atd.chart_context = (const char *) sqlite3_column_text(res, 9);
1899 + atd.when_key = sqlite3_column_int64(res, 10);
1900 + atd.duration = sqlite3_column_int64(res, 11);
1901 + atd.non_clear_duration = sqlite3_column_int64(res, 12);
1902 + atd.flags = sqlite3_column_int64(res, 13);
1903 + atd.delay_up_to_timestamp = sqlite3_column_int64(res, 14);
1904 + atd.info = (const char *) sqlite3_column_text(res, 15);
1905 + atd.exec_code = sqlite3_column_int(res, 16);
1906 + atd.new_status = sqlite3_column_int(res, 17);
1907 + atd.old_status = sqlite3_column_int(res, 18);
1908 + atd.delay = (int) sqlite3_column_int(res, 19);
1909 + atd.new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 20);
1910 + atd.old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 21);
1911 + atd.last_repeat = sqlite3_column_int64(res, 22);
1912 + atd.transition_id = (uuid_t *) sqlite3_column_blob(res, 23);
1913 + atd.global_id = sqlite3_column_int64(res, 24);
1914 + atd.classification = (const char *) sqlite3_column_text(res, 25);
1915 + atd.type = (const char *) sqlite3_column_text(res, 26);
1916 + atd.component = (const char *) sqlite3_column_text(res, 27);
1917 + atd.exec_run_timestamp = sqlite3_column_int64(res, 28);
1918 +
1919 + cb(&atd, data);
1920 }
1921
1922 fail:
1923 rc = sqlite3_finalize(res);
1924 if (unlikely(rc != SQLITE_OK))
1926 - error_report("Failed to finalize statement for sql_health_alarm_log2json_v3");
1925 + error_report("Failed to finalize statement for sql_alert_transitions");
1926
1927 fail_only_drop:
1929 - (void) snprintfz(sql, 511, "DROP TABLE IF EXISTS v_%p", alert_instances);
1930 - (void) db_execute(db_meta, sql);
1928 + if (likely(!transition)) {
1929 + (void)snprintfz(sql, 511, "DROP TABLE IF EXISTS v_%p", nodes);
1930 + (void)db_execute(db_meta, sql);
1931 + buffer_free(command);
1932 + }
1933 +}
1934 +
1935 +#define SQL_BUILD_CONFIG_TARGET_LIST "CREATE TEMP TABLE IF NOT EXISTS c_%p (hash_id blob)"
1936 +
1937 +#define SQL_POPULATE_TEMP_CONFIG_TARGET_TABLE "INSERT INTO c_%p (hash_id) VALUES (@hash_id)"
1938 +
1939 +#define SQL_SEARCH_CONFIG_LIST "SELECT ah.hash_id, alarm, template, on_key, class, component, type, os, hosts, lookup, every, " \
1940 + " units, calc, families, plugin, module, charts, green, red, warn, crit, " \
1941 + " exec, to_key, info, delay, options, repeat, host_labels, p_db_lookup_dimensions, p_db_lookup_method, " \
1942 + " p_db_lookup_options, p_db_lookup_after, p_db_lookup_before, p_update_every, source, chart_labels " \
1943 + " FROM alert_hash ah, c_%p t where ah.hash_id = t.hash_id"
1944 +
1945 +int sql_get_alert_configuration(
1946 + DICTIONARY *configs,
1947 + void (*cb)(struct sql_alert_config_data *, void *),
1948 + void *data,
1949 + bool debug __maybe_unused)
1950 +{
1951 + int added = -1;
1952 + char sql[512];
1953 + int rc;
1954 + sqlite3_stmt *res = NULL;
1955 + BUFFER *command = NULL;
1956 +
1957 + if (unlikely(!configs))
1958 + return added;
1959 +
1960 + snprintfz(sql, 511, SQL_BUILD_CONFIG_TARGET_LIST, configs);
1961 + rc = db_execute(db_meta, sql);
1962 + if (rc)
1963 + return added;
1964 +
1965 + snprintfz(sql, 511, SQL_POPULATE_TEMP_CONFIG_TARGET_TABLE, configs);
1966 +
1967 + // Prepare statement to add things
1968 + rc = sqlite3_prepare_v2(db_meta, sql, -1, &res, 0);
1969 + if (unlikely(rc != SQLITE_OK)) {
1970 + error_report("Failed to prepare statement to INSERT into c_%p", configs);
1971 + goto fail_only_drop;
1972 + }
1973 +
1974 + void *t;
1975 + dfe_start_read(configs, t) {
1976 + uuid_t hash_id;
1977 + uuid_parse( t_dfe.name, hash_id);
1978 +
1979 + rc = sqlite3_bind_blob(res, 1, &hash_id, sizeof(hash_id), SQLITE_STATIC);
1980 + if (unlikely(rc != SQLITE_OK))
1981 + error_report("Failed to bind host_id parameter.");
1982 +
1983 + rc = sqlite3_step_monitored(res);
1984 + if (rc != SQLITE_DONE)
1985 + error_report("Error while populating temp table");
1986 +
1987 + rc = sqlite3_reset(res);
1988 + if (rc != SQLITE_OK)
1989 + error_report("Error while resetting parameters");
1990 + }
1991 + dfe_done(t);
1992 +
1993 + rc = sqlite3_finalize(res);
1994 + if (unlikely(rc != SQLITE_OK)) {
1995 + // log error but continue
1996 + error_report("Failed to finalize statement for sql_get_alert_configuration temp table population");
1997 + }
1998 +
1999 + command = buffer_create(MAX_HEALTH_SQL_SIZE, NULL);
2000 +
2001 + buffer_sprintf(command, SQL_SEARCH_CONFIG_LIST, configs);
2002 +
2003 + rc = sqlite3_prepare_v2(db_meta, buffer_tostring(command), -1, &res, 0);
2004 + if (unlikely(rc != SQLITE_OK)) {
2005 + error_report("Failed to prepare statement sql_get_alert_configuration");
2006 + goto fail_only_drop;
2007 + }
2008 +
2009 + struct sql_alert_config_data acd = {0 };
2010 +
2011 + added = 0;
2012 + int param;
2013 + while (sqlite3_step(res) == SQLITE_ROW) {
2014 + param = 0;
2015 + acd.config_hash_id = (uuid_t *) sqlite3_column_blob(res, param++);
2016 + acd.name = (const char *) sqlite3_column_text(res, param++);
2017 + acd.selectors.on_template = (const char *) sqlite3_column_text(res, param++);
2018 + acd.selectors.on_key = (const char *) sqlite3_column_text(res, param++);
2019 + acd.classification = (const char *) sqlite3_column_text(res, param++);
2020 + acd.component = (const char *) sqlite3_column_text(res, param++);
2021 + acd.type = (const char *) sqlite3_column_text(res, param++);
2022 + acd.selectors.os = (const char *) sqlite3_column_text(res, param++);
2023 + acd.selectors.hosts = (const char *) sqlite3_column_text(res, param++);
2024 + acd.value.db.lookup = (const char *) sqlite3_column_text(res, param++);
2025 + acd.value.every = (const char *) sqlite3_column_text(res, param++);
2026 + acd.value.units = (const char *) sqlite3_column_text(res, param++);
2027 + acd.value.calc = (const char *) sqlite3_column_text(res, param++);
2028 + acd.selectors.families = (const char *) sqlite3_column_text(res, param++);
2029 + acd.selectors.plugin = (const char *) sqlite3_column_text(res, param++);
2030 + acd.selectors.module = (const char *) sqlite3_column_text(res, param++);
2031 + acd.selectors.charts = (const char *) sqlite3_column_text(res, param++);
2032 + acd.status.green = (const char *) sqlite3_column_text(res, param++);
2033 + acd.status.red = (const char *) sqlite3_column_text(res, param++);
2034 + acd.status.warn = (const char *) sqlite3_column_text(res, param++);
2035 + acd.status.crit = (const char *) sqlite3_column_text(res, param++);
2036 + acd.notification.exec = (const char *) sqlite3_column_text(res, param++);
2037 + acd.notification.to_key = (const char *) sqlite3_column_text(res, param++);
2038 + acd.info = (const char *) sqlite3_column_text(res, param++);
2039 + acd.notification.delay = (const char *) sqlite3_column_text(res, param++);
2040 + acd.notification.options = (const char *) sqlite3_column_text(res, param++);
2041 + acd.notification.repeat = (const char *) sqlite3_column_text(res, param++);
2042 + acd.selectors.host_labels = (const char *) sqlite3_column_text(res, param++);
2043 + acd.value.db.dimensions = (const char *) sqlite3_column_text(res, param++);
2044 + acd.value.db.method = (const char *) sqlite3_column_text(res, param++);
2045 + acd.value.db.options = (uint32_t) sqlite3_column_int(res, param++);
2046 + acd.value.db.after = (int32_t) sqlite3_column_int(res, param++);
2047 + acd.value.db.before = (int32_t) sqlite3_column_int(res, param++);
2048 + acd.value.update_every = (int32_t) sqlite3_column_int(res, param++);
2049 + acd.source = (const char *) sqlite3_column_text(res, param++);
2050 + acd.selectors.chart_labels = (const char *) sqlite3_column_text(res, param++);
2051 +
2052 + cb(&acd, data);
2053 + added++;
2054 + }
2055 +
2056 + rc = sqlite3_finalize(res);
2057 + if (unlikely(rc != SQLITE_OK))
2058 + error_report("Failed to finalize statement for sql_get_alert_configuration");
2059 +
2060 +fail_only_drop:
2061 + (void)snprintfz(sql, 511, "DROP TABLE IF EXISTS c_%p", configs);
2062 + (void)db_execute(db_meta, sql);
2063 buffer_free(command);
2064 + return added;
2065 }
2066 +
database/sqlite/sqlite_health.h
+19 -1
@@ -5,6 +5,8 @@
5 #include "../../daemon/common.h"
6 #include "sqlite3.h"
7
8 +struct sql_alert_transition_data;
9 +struct sql_alert_config_data;
10 extern sqlite3 *db_meta;
11 void sql_health_alarm_log_load(RRDHOST *host);
12 void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae);
@@ -17,6 +19,22 @@ int sql_health_get_last_executed_event(RRDHOST *host, ALARM_ENTRY *ae, RRDCALC_S
19 void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *chart);
20 int health_migrate_old_health_log_table(char *table);
21 uint32_t sql_get_alarm_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id, uuid_t *config_hash_id);
20 -void sql_health_alarm_log2json_v3(BUFFER *wb, DICTIONARY *alert_instances, time_t after, time_t before, const char *transition, uint32_t max, bool debug);
22 +void sql_alert_transitions(
23 + DICTIONARY *nodes,
24 + time_t after,
25 + time_t before,
26 + const char *context,
27 + const char *alert_name,
28 + const char *transition,
29 + void (*cb)(struct sql_alert_transition_data *, void *),
30 + void *data,
31 + bool debug);
32 +
33 +int sql_get_alert_configuration(
34 + DICTIONARY *configs,
35 + void (*cb)(struct sql_alert_config_data *, void *),
36 + void *data,
37 + bool debug __maybe_unused);
38 +
39 bool sql_find_alert_transition(const char *transition, void (*cb)(const char *machine_guid, const char *context, time_t alert_id, void *data), void *data);
40 #endif //NETDATA_SQLITE_HEALTH_H
database/sqlite/sqlite_metadata.c
+1 -1
@@ -406,7 +406,7 @@ static int add_host_sysinfo_key_value(const char *name, const char *value, uuid_
406 if (unlikely(rc != SQLITE_OK))
407 goto bind_fail;
408
409 - rc = bind_text_null(res, ++param, value, 1);
409 + rc = bind_text_null(res, ++param, value ? value : "unknown", 0);
410 if (unlikely(rc != SQLITE_OK))
411 goto bind_fail;
412
health/health.c
+3 -3
@@ -33,13 +33,13 @@ void health_entry_flags_to_json_array(BUFFER *wb, const char *key, HEALTH_ENTRY_
33 if(flags & HEALTH_ENTRY_FLAG_EXEC_RUN)
34 buffer_json_add_array_item_string(wb, "EXEC_RUN");
35 if(flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)
36 - buffer_json_add_array_item_string(wb, "FAILED");
36 + buffer_json_add_array_item_string(wb, "EXEC_FAILED");
37 if(flags & HEALTH_ENTRY_FLAG_SILENCED)
38 buffer_json_add_array_item_string(wb, "SILENCED");
39 if(flags & HEALTH_ENTRY_RUN_ONCE)
40 - buffer_json_add_array_item_string(wb, "ONCE");
40 + buffer_json_add_array_item_string(wb, "RUN_ONCE");
41 if(flags & HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS)
42 - buffer_json_add_array_item_string(wb, "IN_PROGRESS");
42 + buffer_json_add_array_item_string(wb, "EXEC_IN_PROGRESS");
43 if(flags & HEALTH_ENTRY_FLAG_IS_REPEATING)
44 buffer_json_add_array_item_string(wb, "RECURRING");
45 if(flags & HEALTH_ENTRY_FLAG_SAVED)
health/health.h
+6 -6
@@ -8,16 +8,16 @@
8 extern unsigned int default_health_enabled;
9
10 typedef enum __attribute__((packed)) {
11 - HEALTH_ENTRY_FLAG_PROCESSED = 0x00000001,
12 - HEALTH_ENTRY_FLAG_UPDATED = 0x00000002,
13 - HEALTH_ENTRY_FLAG_EXEC_RUN = 0x00000004,
14 - HEALTH_ENTRY_FLAG_EXEC_FAILED = 0x00000008,
11 + HEALTH_ENTRY_FLAG_PROCESSED = 0x00000001, // notifications engine has processed this
12 + HEALTH_ENTRY_FLAG_UPDATED = 0x00000002, // there is a more recent update about this transition
13 + HEALTH_ENTRY_FLAG_EXEC_RUN = 0x00000004, // notification script has been run (this is the intent, not the result)
14 + HEALTH_ENTRY_FLAG_EXEC_FAILED = 0x00000008, // notification script couldn't be run
15 HEALTH_ENTRY_FLAG_SILENCED = 0x00000010,
16 HEALTH_ENTRY_RUN_ONCE = 0x00000020,
17 HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS = 0x00000040,
18 HEALTH_ENTRY_FLAG_IS_REPEATING = 0x00000080,
19 - HEALTH_ENTRY_FLAG_SAVED = 0x10000000,
20 - HEALTH_ENTRY_FLAG_ACLK_QUEUED = 0x20000000,
19 + HEALTH_ENTRY_FLAG_SAVED = 0x10000000, // Saved to SQL
20 + HEALTH_ENTRY_FLAG_ACLK_QUEUED = 0x20000000, // Sent to Netdata Cloud
21 HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION = 0x80000000,
22 } HEALTH_ENTRY_FLAGS;
23
libnetdata/buffer/buffer.c
+3 -1
@@ -315,6 +315,8 @@ void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value
315
316 if(add_anonymous_object)
317 buffer_fast_strcat(wb, "{", 1);
318 +
319 + wb->content_type = CT_APPLICATION_JSON;
320 }
321
322 void buffer_json_finalize(BUFFER *wb) {
@@ -503,7 +505,7 @@ int buffer_unittest(void) {
505 return errors;
506 }
507
506 -#ifdef ENABLE_HTTPD
508 +#ifdef ENABLE_H2O
509 h2o_iovec_t buffer_to_h2o_iovec(BUFFER *wb) {
510 h2o_iovec_t ret;
511 ret.base = wb->buffer;
libnetdata/buffer/buffer.h
+2 -2
@@ -6,7 +6,7 @@
6 #include "../string/utf8.h"
7 #include "../libnetdata.h"
8
9 -#ifdef ENABLE_HTTPD
9 +#ifdef ENABLE_H2O
10 #include "h2o/memory.h"
11 #endif
12
@@ -133,7 +133,7 @@ void buffer_char_replace(BUFFER *wb, char from, char to);
133
134 void buffer_print_sn_flags(BUFFER *wb, SN_FLAGS flags, bool send_anomaly_bit);
135
136 -#ifdef ENABLE_HTTPD
136 +#ifdef ENABLE_H2O
137 h2o_iovec_t buffer_to_h2o_iovec(BUFFER *wb);
138 #endif
139
libnetdata/config/appconfig.c
+2 -2
@@ -518,9 +518,9 @@ int appconfig_get_boolean_ondemand(struct config *root, const char *section, con
518 s = appconfig_get(root, section, name, s);
519 if(!s) return value;
520
521 - if(!strcmp(s, "yes"))
521 + if(!strcmp(s, "yes") || !strcmp(s, "true") || !strcmp(s, "on"))
522 return CONFIG_BOOLEAN_YES;
523 - else if(!strcmp(s, "no"))
523 + else if(!strcmp(s, "no") || !strcmp(s, "false") || !strcmp(s, "off"))
524 return CONFIG_BOOLEAN_NO;
525 else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
526 return CONFIG_BOOLEAN_AUTO;
libnetdata/libnetdata.h
+81 -18
@@ -11,6 +11,21 @@ extern "C" {
11 #include <config.h>
12 #endif
13
14 +#ifdef ENABLE_LZ4
15 +#define ENABLE_RRDPUSH_COMPRESSION 1
16 +#endif
17 +
18 +#ifdef ENABLE_OPENSSL
19 +#define ENABLE_HTTPS 1
20 +#endif
21 +
22 +#ifdef HAVE_LIBDATACHANNEL
23 +#define ENABLE_WEBRTC 1
24 +#endif
25 +
26 +#define STRINGIFY(x) #x
27 +#define TOSTRING(x) STRINGIFY(x)
28 +
29 #define JUDYHS_INDEX_SIZE_ESTIMATE(key_bytes) (((key_bytes) + sizeof(Word_t) - 1) / sizeof(Word_t) * 4)
30
31 #if defined(NETDATA_DEV_MODE) && !defined(NETDATA_INTERNAL_CHECKS)
@@ -592,32 +607,80 @@ char *find_and_replace(const char *src, const char *find, const char *replace, c
607 #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
608
609 #ifdef ENV32BIT
610 +
611 +typedef struct bitmapX {
612 + uint32_t bits;
613 + uint32_t data[];
614 +} BITMAPX;
615 +
616 typedef struct bitmap256 {
596 - uint32_t data[8];
617 + uint32_t bits;
618 + uint32_t data[256 / 32];
619 } BITMAP256;
620
599 -#define bitmap256_get_bit(ptr, idx) (((ptr)->data[(idx) >> 5] & (1ULL << ((idx) & 31))) != 0)
600 -static inline void bitmap256_set_bit(BITMAP256 *ptr, uint8_t idx, bool value) {
601 - uint32_t mask = 1U << (idx & 31);
602 - if (value)
603 - ptr->data[idx >> 5] |= mask;
604 - else
605 - ptr->data[idx >> 5] &= ~mask;
621 +typedef struct bitmap1024 {
622 + uint32_t bits;
623 + uint32_t data[1024 / 32];
624 +} BITMAP1024;
625 +
626 +static inline BITMAPX *bitmapX_create(uint32_t bits) {
627 + BITMAPX *bmp = (BITMAPX *)callocz(1, sizeof(BITMAPX) + sizeof(uint32_t) * ((bits + 31) / 32));
628 + uint32_t *p = (uint32_t *)&bmp->bits;
629 + *p = bits;
630 + return bmp;
631 }
607 -#else // 64bit
632 +
633 +#define bitmapX_get_bit(ptr, idx) ((ptr)->data[(idx) >> 5] & (1U << ((idx) & 31)))
634 +#define bitmapX_set_bit(ptr, idx, value) do { \
635 + register uint32_t _bitmask = 1U << ((idx) & 31); \
636 + if (value) \
637 + (ptr)->data[(idx) >> 5] |= _bitmask; \
638 + else \
639 + (ptr)->data[(idx) >> 5] &= ~_bitmask; \
640 +} while(0)
641 +
642 +#else // 64bit version of bitmaps
643 +
644 +typedef struct bitmapX {
645 + uint32_t bits;
646 + uint64_t data[];
647 +} BITMAPX;
648 +
649 typedef struct bitmap256 {
609 - uint64_t data[4];
650 + uint32_t bits;
651 + uint64_t data[256 / 64];
652 } BITMAP256;
653
612 -#define bitmap256_get_bit(ptr, idx) ((ptr)->data[(idx) >> 6] & (1ULL << ((idx) & 63)))
613 -static inline void bitmap256_set_bit(BITMAP256 *ptr, uint8_t idx, bool value) {
614 - uint64_t mask = 1ULL << (idx & 63);
615 - if (value)
616 - ptr->data[idx >> 6] |= mask;
617 - else
618 - ptr->data[idx >> 6] &= ~mask;
654 +typedef struct bitmap1024 {
655 + uint32_t bits;
656 + uint64_t data[1024 / 64];
657 +} BITMAP1024;
658 +
659 +static inline BITMAPX *bitmapX_create(uint32_t bits) {
660 + BITMAPX *bmp = (BITMAPX *)callocz(1, sizeof(BITMAPX) + sizeof(uint64_t) * ((bits + 63) / 64));
661 + bmp->bits = bits;
662 + return bmp;
663 }
620 -#endif // 64bit
664 +
665 +#define bitmapX_get_bit(ptr, idx) ((ptr)->data[(idx) >> 6] & (1ULL << ((idx) & 63)))
666 +#define bitmapX_set_bit(ptr, idx, value) do { \
667 + register uint64_t _bitmask = 1ULL << ((idx) & 63); \
668 + if (value) \
669 + (ptr)->data[(idx) >> 6] |= _bitmask; \
670 + else \
671 + (ptr)->data[(idx) >> 6] &= ~_bitmask; \
672 +} while(0)
673 +
674 +#endif // 64bit version of bitmaps
675 +
676 +#define BITMAPX_INITIALIZER(wanted_bits) { .bits = (wanted_bits), .data = {0} }
677 +#define BITMAP256_INITIALIZER (BITMAP256)BITMAPX_INITIALIZER(256)
678 +#define BITMAP1024_INITIALIZER (BITMAP1024)BITMAPX_INITIALIZER(1024)
679 +#define bitmap256_get_bit(ptr, idx) bitmapX_get_bit((BITMAPX *)ptr, idx)
680 +#define bitmap256_set_bit(ptr, idx, value) bitmapX_set_bit((BITMAPX *)ptr, idx, value)
681 +#define bitmap1024_get_bit(ptr, idx) bitmapX_get_bit((BITMAPX *)ptr, idx)
682 +#define bitmap1024_set_bit(ptr, idx, value) bitmapX_set_bit((BITMAPX *)ptr, idx, value)
683 +
684
685 #define COMPRESSION_MAX_MSG_SIZE 0x4000
686 #define PLUGINSD_LINE_MAX (COMPRESSION_MAX_MSG_SIZE - 1024)
netdata-installer.sh
+5
@@ -1285,6 +1285,11 @@ if [ "$(id -u)" -eq 0 ]; then
1285 run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network-helper.sh"
1286 run chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network-helper.sh"
1287 fi
1288 +
1289 + if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/local-listeners" ]; then
1290 + run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/local-listeners"
1291 + run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/local-listeners"
1292 + fi
1293 else
1294 # non-privileged user installation
1295 run chown "${NETDATA_USER}:${NETDATA_GROUP}" "${NETDATA_LOG_DIR}"
netdata.spec.in
+3
@@ -537,6 +537,9 @@ rm -rf "${RPM_BUILD_ROOT}"
537 %attr(4750,root,netdata) %{_libexecdir}/%{name}/plugins.d/cgroup-network
538 %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/cgroup-network-helper.sh
539
540 +# local-listeners detects the local processes that are listening for connections
541 +%attr(4750,root,netdata) %{_libexecdir}/%{name}/plugins.d/local-listeners
542 +
543 # Enforce 0644 for files and 0755 for directories
544 # for the netdata web directory
545 %defattr(0644,root,root,0755)
packaging/docker/Dockerfile
+1
@@ -104,6 +104,7 @@ RUN chown -R root:root \
104 chmod 0755 /usr/libexec/netdata/plugins.d/*.plugin && \
105 chmod 4755 \
106 /usr/libexec/netdata/plugins.d/cgroup-network \
107 + /usr/libexec/netdata/plugins.d/local-listeners \
108 /usr/libexec/netdata/plugins.d/apps.plugin \
109 /usr/libexec/netdata/plugins.d/debugfs.plugin && \
110 if [ -f /usr/libexec/netdata/plugins.d/freeipmi.plugin ]; then \
packaging/makeself/install-or-update.sh
+2 -2
@@ -172,7 +172,7 @@ fi
172
173 progress "changing plugins ownership and permissions"
174
175 -for x in apps.plugin perf.plugin slabinfo.plugin debugfs.plugin freeipmi.plugin ioping cgroup-network ebpf.plugin nfacct.plugin xenstat.plugin python.d.plugin charts.d.plugin go.d.plugin ioping.plugin cgroup-network-helper.sh; do
175 +for x in apps.plugin perf.plugin slabinfo.plugin debugfs.plugin freeipmi.plugin ioping cgroup-network local-listeners ebpf.plugin nfacct.plugin xenstat.plugin python.d.plugin charts.d.plugin go.d.plugin ioping.plugin cgroup-network-helper.sh; do
176 f="usr/libexec/netdata/plugins.d/${x}"
177 if [ -f "${f}" ]; then
178 run chown root:${NETDATA_GROUP} "${f}"
@@ -198,7 +198,7 @@ else
198 done
199 fi
200
201 -for x in freeipmi.plugin ioping cgroup-network ebpf.plugin nfacct.plugin xenstat.plugin; do
201 +for x in freeipmi.plugin ioping cgroup-network local-listeners ebpf.plugin nfacct.plugin xenstat.plugin; do
202 f="usr/libexec/netdata/plugins.d/${x}"
203
204 if [ -f "${f}" ]; then
registry/registry_internals.h
+1
@@ -50,6 +50,7 @@ struct registry {
50 char *db_filename;
51 char *log_filename;
52 char *machine_guid_filename;
53 + char *session_key_filename;
54
55 // open files
56 FILE *log_fp;
streaming/compression.c
+1 -1
@@ -1,6 +1,6 @@
1 #include "rrdpush.h"
2
3 -#ifdef ENABLE_COMPRESSION
3 +#ifdef ENABLE_RRDPUSH_COMPRESSION
4 #include "lz4.h"
5
6 #define STREAM_COMPRESSION_MSG "STREAM_COMPRESSION"
streaming/receiver.c
+10 -10
@@ -28,7 +28,7 @@ void receiver_state_free(struct receiver_state *rpt) {
28 close(rpt->fd);
29 }
30
31 -#ifdef ENABLE_COMPRESSION
31 +#ifdef ENABLE_RRDPUSH_COMPRESSION
32 rrdpush_decompressor_destroy(&rpt->decompressor);
33 #endif
34
@@ -111,7 +111,7 @@ static inline bool receiver_read_uncompressed(struct receiver_state *r) {
111 return true;
112 }
113
114 -#ifdef ENABLE_COMPRESSION
114 +#ifdef ENABLE_RRDPUSH_COMPRESSION
115 static inline bool receiver_read_compressed(struct receiver_state *r) {
116
117 internal_fatal(r->reader.read_buffer[r->reader.read_len] != '\0',
@@ -217,11 +217,11 @@ static inline bool receiver_read_compressed(struct receiver_state *r) {
217
218 return true;
219 }
220 -#else // !ENABLE_COMPRESSION
220 +#else // !ENABLE_RRDPUSH_COMPRESSION
221 static inline bool receiver_read_compressed(struct receiver_state *r) {
222 return receiver_read_uncompressed(r);
223 }
224 -#endif // ENABLE_COMPRESSION
224 +#endif // ENABLE_RRDPUSH_COMPRESSION
225
226 /* Produce a full line if one exists, statefully return where we start next time.
227 * When we hit the end of the buffer with a partial line move it to the beginning for the next fill.
@@ -331,7 +331,7 @@ static size_t streaming_parser(struct receiver_state *rpt, struct plugind *cd, i
331
332 bool compressed_connection = false;
333
334 -#ifdef ENABLE_COMPRESSION
334 +#ifdef ENABLE_RRDPUSH_COMPRESSION
335 if(stream_has_capability(rpt, STREAM_CAP_COMPRESSION)) {
336 compressed_connection = true;
337 rrdpush_decompressor_reset(&rpt->decompressor);
@@ -609,11 +609,11 @@ static void rrdpush_receive(struct receiver_state *rpt)
609 rpt->config.rrdpush_replication_step = appconfig_get_number(&stream_config, rpt->key, "seconds per replication step", rpt->config.rrdpush_replication_step);
610 rpt->config.rrdpush_replication_step = appconfig_get_number(&stream_config, rpt->machine_guid, "seconds per replication step", rpt->config.rrdpush_replication_step);
611
612 -#ifdef ENABLE_COMPRESSION
613 - rpt->config.rrdpush_compression = default_compression_enabled;
612 +#ifdef ENABLE_RRDPUSH_COMPRESSION
613 + rpt->config.rrdpush_compression = default_rrdpush_compression_enabled;
614 rpt->config.rrdpush_compression = appconfig_get_boolean(&stream_config, rpt->key, "enable compression", rpt->config.rrdpush_compression);
615 rpt->config.rrdpush_compression = appconfig_get_boolean(&stream_config, rpt->machine_guid, "enable compression", rpt->config.rrdpush_compression);
616 -#endif //ENABLE_COMPRESSION
616 +#endif // ENABLE_RRDPUSH_COMPRESSION
617
618 (void)appconfig_set_default(&stream_config, rpt->machine_guid, "host tags", (rpt->tags)?rpt->tags:"");
619
@@ -707,12 +707,12 @@ static void rrdpush_receive(struct receiver_state *rpt)
707 snprintfz(cd.fullfilename, FILENAME_MAX, "%s:%s", rpt->client_ip, rpt->client_port);
708 snprintfz(cd.cmd, PLUGINSD_CMD_MAX, "%s:%s", rpt->client_ip, rpt->client_port);
709
710 -#ifdef ENABLE_COMPRESSION
710 +#ifdef ENABLE_RRDPUSH_COMPRESSION
711 if (stream_has_capability(rpt, STREAM_CAP_COMPRESSION)) {
712 if (!rpt->config.rrdpush_compression)
713 rpt->capabilities &= ~STREAM_CAP_COMPRESSION;
714 }
715 -#endif
715 +#endif // ENABLE_RRDPUSH_COMPRESSION
716
717 {
718 // netdata_log_info("STREAM %s [receive from [%s]:%s]: initializing communication...", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port);
streaming/rrdpush.c
+5 -5
@@ -39,8 +39,8 @@ struct config stream_config = {
39 };
40
41 unsigned int default_rrdpush_enabled = 0;
42 -#ifdef ENABLE_COMPRESSION
43 -unsigned int default_compression_enabled = 1;
42 +#ifdef ENABLE_RRDPUSH_COMPRESSION
43 +unsigned int default_rrdpush_compression_enabled = 1;
44 #endif
45 char *default_rrdpush_destination = NULL;
46 char *default_rrdpush_api_key = NULL;
@@ -142,9 +142,9 @@ int rrdpush_init() {
142
143 rrdhost_free_orphan_time_s = config_get_number(CONFIG_SECTION_DB, "cleanup orphan hosts after secs", rrdhost_free_orphan_time_s);
144
145 -#ifdef ENABLE_COMPRESSION
146 - default_compression_enabled = (unsigned int)appconfig_get_boolean(&stream_config, CONFIG_SECTION_STREAM,
147 - "enable compression", default_compression_enabled);
145 +#ifdef ENABLE_RRDPUSH_COMPRESSION
146 + default_rrdpush_compression_enabled = (unsigned int)appconfig_get_boolean(&stream_config, CONFIG_SECTION_STREAM,
147 + "enable compression", default_rrdpush_compression_enabled);
148 #endif
149
150 if(default_rrdpush_enabled && (!default_rrdpush_destination || !*default_rrdpush_destination || !default_rrdpush_api_key || !*default_rrdpush_api_key)) {
streaming/rrdpush.h
+12 -12
@@ -50,11 +50,11 @@ typedef enum {
50 // needed for negotiating errors between parent and child
51 } STREAM_CAPABILITIES;
52
53 -#ifdef ENABLE_COMPRESSION
53 +#ifdef ENABLE_RRDPUSH_COMPRESSION
54 #define STREAM_HAS_COMPRESSION STREAM_CAP_COMPRESSION
55 #else
56 #define STREAM_HAS_COMPRESSION 0
57 -#endif // ENABLE_COMPRESSION
57 +#endif // ENABLE_RRDPUSH_COMPRESSION
58
59 STREAM_CAPABILITIES stream_our_capabilities(RRDHOST *host, bool sender);
60
@@ -118,7 +118,7 @@ typedef struct {
118 char *kernel_version;
119 } stream_encoded_t;
120
121 -#ifdef ENABLE_COMPRESSION
121 +#ifdef ENABLE_RRDPUSH_COMPRESSION
122 // signature MUST end with a newline
123 #define RRDPUSH_COMPRESSION_SIGNATURE ((uint32_t)('z' | 0x80) | (0x80 << 8) | (0x80 << 16) | ('\n' << 24))
124 #define RRDPUSH_COMPRESSION_SIGNATURE_MASK ((uint32_t)0xff | (0x80 << 8) | (0x80 << 16) | (0xff << 24))
@@ -262,9 +262,9 @@ struct sender_state {
262
263 uint16_t hops;
264
265 -#ifdef ENABLE_COMPRESSION
265 +#ifdef ENABLE_RRDPUSH_COMPRESSION
266 struct compressor_state compressor;
267 -#endif
267 +#endif // ENABLE_RRDPUSH_COMPRESSION
268
269 #ifdef ENABLE_HTTPS
270 NETDATA_SSL ssl; // structure used to encrypt the connection
@@ -416,9 +416,9 @@ struct receiver_state {
416
417 time_t replication_first_time_t;
418
419 -#ifdef ENABLE_COMPRESSION
419 +#ifdef ENABLE_RRDPUSH_COMPRESSION
420 struct decompressor_state decompressor;
421 -#endif
421 +#endif // ENABLE_RRDPUSH_COMPRESSION
422 /*
423 struct {
424 uint32_t count;
@@ -440,9 +440,9 @@ struct rrdpush_destinations {
440 };
441
442 extern unsigned int default_rrdpush_enabled;
443 -#ifdef ENABLE_COMPRESSION
444 -extern unsigned int default_compression_enabled;
445 -#endif
443 +#ifdef ENABLE_RRDPUSH_COMPRESSION
444 +extern unsigned int default_rrdpush_compression_enabled;
445 +#endif // ENABLE_RRDPUSH_COMPRESSION
446 extern char *default_rrdpush_destination;
447 extern char *default_rrdpush_api_key;
448 extern char *default_rrdpush_send_charts_matching;
@@ -500,9 +500,9 @@ int connect_to_one_of_destinations(
500
501 void rrdpush_signal_sender_to_wake_up(struct sender_state *s);
502
503 -#ifdef ENABLE_COMPRESSION
503 +#ifdef ENABLE_RRDPUSH_COMPRESSION
504 struct compressor_state *create_compressor();
505 -#endif
505 +#endif // ENABLE_RRDPUSH_COMPRESSION
506
507 void rrdpush_reset_destinations_postpone_time(RRDHOST *host);
508 const char *stream_handshake_error_to_string(STREAM_HANDSHAKE handshake_error);
streaming/sender.c
+6 -6
@@ -66,7 +66,7 @@ BUFFER *sender_start(struct sender_state *s) {
66
67 static inline void rrdpush_sender_thread_close_socket(RRDHOST *host);
68
69 -#ifdef ENABLE_COMPRESSION
69 +#ifdef ENABLE_RRDPUSH_COMPRESSION
70 /*
71 * In case of stream compression buffer overflow
72 * Inform the user through the error log file and
@@ -117,7 +117,7 @@ void sender_commit(struct sender_state *s, BUFFER *wb, STREAM_TRAFFIC_TYPE type)
117 s->buffer->max_size = (src_len + 1) * SENDER_BUFFER_ADAPT_TO_TIMES_MAX_SIZE;
118 }
119
120 -#ifdef ENABLE_COMPRESSION
120 +#ifdef ENABLE_RRDPUSH_COMPRESSION
121 if (stream_has_capability(s, STREAM_CAP_COMPRESSION) && s->compressor.initialized) {
122 while(src_len) {
123 size_t size_to_compress = src_len;
@@ -590,11 +590,11 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
590 // reset our capabilities to default
591 s->capabilities = stream_our_capabilities(host, true);
592
593 -#ifdef ENABLE_COMPRESSION
593 +#ifdef ENABLE_RRDPUSH_COMPRESSION
594 // If we don't want compression, remove it from our capabilities
595 if(!(s->flags & SENDER_FLAG_COMPRESSION))
596 s->capabilities &= ~STREAM_CAP_COMPRESSION;
597 -#endif // ENABLE_COMPRESSION
597 +#endif // ENABLE_RRDPUSH_COMPRESSION
598
599 /* TODO: During the implementation of #7265 switch the set of variables to HOST_* and CONTAINER_* if the
600 version negotiation resulted in a high enough version.
@@ -756,12 +756,12 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
756 if(!rrdpush_sender_validate_response(host, s, http, bytes))
757 return false;
758
759 -#ifdef ENABLE_COMPRESSION
759 +#ifdef ENABLE_RRDPUSH_COMPRESSION
760 if(stream_has_capability(s, STREAM_CAP_COMPRESSION))
761 rrdpush_compressor_reset(&s->compressor);
762 else
763 rrdpush_compressor_destroy(&s->compressor);
764 -#endif //ENABLE_COMPRESSION
764 +#endif // ENABLE_RRDPUSH_COMPRESSION
765
766 log_sender_capabilities(s);
767
web/api/queries/rrdr.h
+6 -5
@@ -52,11 +52,12 @@ typedef enum rrdr_options {
52 } RRDR_OPTIONS;
53
54 typedef enum context_v2_options {
55 - CONTEXT_V2_OPTION_MINIFY = (1 << 0), // remove JSON spaces and newlines from JSON output
56 - CONTEXT_V2_OPTION_DEBUG = (1 << 1), // show the request
57 - CONTEXT_V2_OPTION_ALERT_CONFIGURATIONS = (1 << 2), // include alert configurations
58 - CONTEXT_V2_OPTION_ALERT_TRANSITIONS = (1 << 3), // include alert transitions
59 - CONTEXT_V2_OPTION_ALERT_INSTANCES = (1 << 4), // include alert instances
55 + CONTEXT_V2_OPTION_MINIFY = (1 << 0), // remove JSON spaces and newlines from JSON output
56 + CONTEXT_V2_OPTION_DEBUG = (1 << 1), // show the request
57 + CONTEXT_V2_OPTION_ALERTS_WITH_CONFIGURATIONS = (1 << 2), // include alert configurations (used by /api/v2/alert_transitions)
58 + CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES = (1 << 3), // include alert instances (used by /api/v2/alerts)
59 + CONTEXT_V2_OPTION_ALERTS_WITH_VALUES = (1 << 4), // include alert latest values (used by /api/v2/alerts)
60 + CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY = (1 << 5), // include alerts summary counters (used by /api/v2/alerts)
61 } CONTEXTS_V2_OPTIONS;
62
63 typedef enum context_v2_alert_status {
web/api/web_api_v1.c
+8 -12
@@ -57,9 +57,10 @@ static struct {
57 } contexts_v2_options[] = {
58 {"minify" , 0 , CONTEXT_V2_OPTION_MINIFY}
59 , {"debug" , 0 , CONTEXT_V2_OPTION_DEBUG}
60 - , {"config" , 0 , CONTEXT_V2_OPTION_ALERT_CONFIGURATIONS}
61 - , {"transitions" , 0 , CONTEXT_V2_OPTION_ALERT_TRANSITIONS}
62 - , {"instances" , 0 , CONTEXT_V2_OPTION_ALERT_INSTANCES}
60 + , {"config" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_CONFIGURATIONS}
61 + , {"instances" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES}
62 + , {"values" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_VALUES}
63 + , {"summary" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY}
64 , {NULL , 0 , 0}
65 };
66
@@ -1235,12 +1236,7 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
1236 host_functions2json(host, wb);
1237 host_collectors(host, wb);
1238
1238 -#ifdef DISABLE_CLOUD
1239 - buffer_json_member_add_boolean(wb, "cloud-enabled", false);
1240 -#else
1241 - buffer_json_member_add_boolean(wb, "cloud-enabled",
1242 - appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", true));
1243 -#endif
1239 + buffer_json_member_add_boolean(wb, "cloud-enabled", netdata_cloud_enabled);
1240
1241 #ifdef ENABLE_ACLK
1242 buffer_json_member_add_boolean(wb, "cloud-available", true);
@@ -1266,12 +1262,12 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
1262 buffer_json_member_add_boolean(wb, "web-enabled", web_server_mode != WEB_SERVER_MODE_NONE);
1263 buffer_json_member_add_boolean(wb, "stream-enabled", default_rrdpush_enabled);
1264
1269 -#ifdef ENABLE_COMPRESSION
1265 +#ifdef ENABLE_RRDPUSH_COMPRESSION
1266 buffer_json_member_add_boolean(wb, "stream-compression",
1267 host->sender && stream_has_capability(host->sender, STREAM_CAP_COMPRESSION));
1272 -#else
1268 +#else // ! ENABLE_RRDPUSH_COMPRESSION
1269 buffer_json_member_add_boolean(wb, "stream-compression", false);
1274 -#endif //ENABLE_COMPRESSION
1270 +#endif // ENABLE_RRDPUSH_COMPRESSION
1271
1272 #ifdef ENABLE_HTTPS
1273 buffer_json_member_add_boolean(wb, "https-enabled", true);
web/api/web_api_v2.c
+82 -22
@@ -21,9 +21,9 @@ static int web_client_api_request_v2_contexts_internal(RRDHOST *host __maybe_unu
21 req.scope_nodes = value;
22 else if(!strcmp(name, "nodes"))
23 req.nodes = value;
24 - else if((mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS)) && !strcmp(name, "scope_contexts"))
24 + else if((mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS | CONTEXTS_V2_ALERT_TRANSITIONS)) && !strcmp(name, "scope_contexts"))
25 req.scope_contexts = value;
26 - else if((mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS)) && !strcmp(name, "contexts"))
26 + else if((mode & (CONTEXTS_V2_CONTEXTS | CONTEXTS_V2_SEARCH | CONTEXTS_V2_ALERTS | CONTEXTS_V2_ALERT_TRANSITIONS)) && !strcmp(name, "contexts"))
27 req.contexts = value;
28 else if((mode & CONTEXTS_V2_SEARCH) && !strcmp(name, "q"))
29 req.q = value;
@@ -35,20 +35,34 @@ static int web_client_api_request_v2_contexts_internal(RRDHOST *host __maybe_unu
35 req.before = str2l(value);
36 else if(!strcmp(name, "timeout"))
37 req.timeout_ms = str2l(value);
38 - else if(mode & CONTEXTS_V2_ALERTS) {
39 - if(!strcmp(name, "status"))
40 - req.alerts.status = web_client_api_request_v2_alert_status(value);
41 - else if (!strcmp(name, "last")) {
42 - req.alerts.last = strtoul(value, NULL, 0);
43 - } else if (!strcmp(name, "transition")) {
44 - req.alerts.transition = value;
45 - } else if (!strcmp(name, "alert")) {
38 + else if(mode & (CONTEXTS_V2_ALERTS | CONTEXTS_V2_ALERT_TRANSITIONS)) {
39 + if (!strcmp(name, "alert"))
40 req.alerts.alert = value;
41 + else if (!strcmp(name, "transition"))
42 + req.alerts.transition = value;
43 + else if(mode & CONTEXTS_V2_ALERTS) {
44 + if (!strcmp(name, "status"))
45 + req.alerts.status = web_client_api_request_v2_alert_status(value);
46 + }
47 + else if(mode & CONTEXTS_V2_ALERT_TRANSITIONS) {
48 + if (!strcmp(name, "last"))
49 + req.alerts.last = strtoul(value, NULL, 0);
50 + else if(!strcmp(name, "context"))
51 + req.contexts = value;
52 + else if (!strcmp(name, "anchor_gi")) {
53 + req.alerts.global_id_anchor = str2ull(value, NULL);
54 + }
55 + else {
56 + for(int i = 0; i < ATF_TOTAL_ENTRIES ;i++) {
57 + if(!strcmp(name, alert_transition_facets[i].query_param))
58 + req.alerts.facets[i] = value;
59 + }
60 + }
61 }
62 }
63 }
64
51 - if ((mode & CONTEXTS_V2_ALERTS) && (req.options & CONTEXT_V2_OPTION_ALERT_INSTANCES) && !req.alerts.last)
65 + if ((mode & CONTEXTS_V2_ALERT_TRANSITIONS) && !req.alerts.last)
66 req.alerts.last = 1;
67
68 buffer_flush(w->response.data);
@@ -56,6 +70,10 @@ static int web_client_api_request_v2_contexts_internal(RRDHOST *host __maybe_unu
70 return rrdcontext_to_json_v2(w->response.data, &req, mode);
71 }
72
73 +static int web_client_api_request_v2_alert_transitions(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
74 + return web_client_api_request_v2_contexts_internal(host, w, url, CONTEXTS_V2_ALERT_TRANSITIONS | CONTEXTS_V2_NODES);
75 +}
76 +
77 static int web_client_api_request_v2_alerts(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
78 return web_client_api_request_v2_contexts_internal(host, w, url, CONTEXTS_V2_ALERTS | CONTEXTS_V2_NODES);
79 }
@@ -80,14 +98,52 @@ static int web_client_api_request_v2_nodes(RRDHOST *host __maybe_unused, struct
98 return web_client_api_request_v2_contexts_internal(host, w, url, CONTEXTS_V2_NODES | CONTEXTS_V2_NODES_INFO);
99 }
100
83 -static int web_client_api_request_v2_nodes_instances(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
84 - return web_client_api_request_v2_contexts_internal(host, w, url, CONTEXTS_V2_NODES | CONTEXTS_V2_NODES_INSTANCES | CONTEXTS_V2_AGENTS | CONTEXTS_V2_AGENTS_INFO | CONTEXTS_V2_VERSIONS);
101 +static int web_client_api_request_v2_info(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
102 + return web_client_api_request_v2_contexts_internal(host, w, url, CONTEXTS_V2_AGENTS | CONTEXTS_V2_AGENTS_INFO);
103 +}
104 +
105 +static int web_client_api_request_v2_node_instances(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
106 + return web_client_api_request_v2_contexts_internal(host, w, url, CONTEXTS_V2_NODES | CONTEXTS_V2_NODE_INSTANCES | CONTEXTS_V2_AGENTS | CONTEXTS_V2_AGENTS_INFO | CONTEXTS_V2_VERSIONS);
107 }
108
109 static int web_client_api_request_v2_weights(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
110 return web_client_api_request_weights(host, w, url, WEIGHTS_METHOD_VALUE, WEIGHTS_FORMAT_MULTINODE, 2);
111 }
112
113 +static int web_client_api_request_v2_claim(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
114 + return api_v2_claim(w, url);
115 +}
116 +
117 +static int web_client_api_request_v2_alert_config(RRDHOST *host __maybe_unused, struct web_client *w, char *url) {
118 + const char *config = NULL;
119 +
120 + while(url) {
121 + char *value = strsep_skip_consecutive_separators(&url, "&");
122 + if(!value || !*value) continue;
123 +
124 + char *name = strsep_skip_consecutive_separators(&value, "=");
125 + if(!name || !*name) continue;
126 + if(!value || !*value) continue;
127 +
128 + // name and value are now the parameters
129 + // they are not null and not empty
130 +
131 + if(!strcmp(name, "config"))
132 + config = value;
133 + }
134 +
135 + buffer_flush(w->response.data);
136 +
137 + if(!config) {
138 + w->response.data->content_type = CT_TEXT_PLAIN;
139 + buffer_strcat(w->response.data, "A config hash ID is required. Add ?config=UUID query param");
140 + return HTTP_RESP_BAD_REQUEST;
141 + }
142 +
143 + return contexts_v2_alert_config_to_json(w, config);
144 +}
145 +
146 +
147 #define GROUP_BY_KEY_MAX_LENGTH 30
148 static struct {
149 char group_by[GROUP_BY_KEY_MAX_LENGTH + 1];
@@ -385,15 +441,19 @@ static int web_client_api_request_v2_webrtc(RRDHOST *host __maybe_unused, struct
441 }
442
443 static struct web_api_command api_commands_v2[] = {
388 - {"data", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_data},
389 - {"nodes", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_nodes},
390 - {"nodes_instances", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_nodes_instances},
391 - {"contexts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_contexts},
392 - {"weights", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_weights},
393 - {"versions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_versions},
394 - {"functions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_functions},
395 - {"alerts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alerts},
396 - {"q", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_q},
444 + {"data", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_data},
445 + {"info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_info},
446 + {"nodes", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_nodes},
447 + {"node_instances", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_node_instances},
448 + {"contexts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_contexts},
449 + {"weights", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_weights},
450 + {"versions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_versions},
451 + {"functions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_functions},
452 + {"alerts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alerts},
453 + {"alert_transitions", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alert_transitions},
454 + {"alert_config", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_alert_config},
455 + {"claim", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_claim},
456 + {"q", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v2_q},
457
458 {"rtc_offer", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v2_webrtc},
459
web/rtc/webrtc.c
+1 -1
@@ -322,7 +322,7 @@ static void webrtc_execute_api_request(WEBRTC_DC *chan, const char *request, siz
322 chan->conn->pc, chan->dc, w->response.code, response_size);
323 }
324
325 -#if defined(ENABLE_COMPRESSION)
325 +#if defined(ENABLE_LZ4)
326 int max_compressed_size = LZ4_compressBound((int)response_size);
327 char *compressed = mallocz(max_compressed_size);
328
web/server/h2o/h2o_utils.c renamed
web/server/h2o/h2o_utils.h renamed
web/server/h2o/http_server.c renamed
+1 -1
@@ -284,7 +284,7 @@ static int hdl_netdata_conf(h2o_handler_t *self, h2o_req_t *req)
284
285 #define POLL_INTERVAL 100
286
287 -void *httpd_main(void *ptr) {
287 +void *h2o_main(void *ptr) {
288 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
289
290 h2o_pathconf_t *pathconf;
web/server/h2o/http_server.h renamed
+1 -1
@@ -3,7 +3,7 @@
3 #ifndef HTTP_SERVER_H
4 #define HTTP_SERVER_H
5
6 -void *httpd_main(void * ptr);
6 +void *h2o_main(void * ptr);
7
8 int httpd_is_enabled();
9
web/server/h2o/libh2o renamed