@cryptotaxi247 / netdata-1 / commits / 171d8f5d0

Revert "Easily disable alarms, by persisting the silencers configuration (#6274)"

This reverts commit 60a73e90de2aa1c2eaae2ebbc45dd1fb96034df2. Emergency rollback of potential culprit as per issue #6356 Will be re-merging the change after investigation

Pavlos Emm. Katsoulakis committed Jun 28, 2019 at 08:27 UTC 171d8f5d01f17dddbd531139b86e1a1c96f95b0d
40 files changed +125 -1637
CMakeLists.txt
+1 -16
@@ -130,14 +130,6 @@ set(NETDATA_COMMON_CFLAGS ${NETDATA_COMMON_CFLAGS} ${OPENSSL_CFLAGS_OTHER})
130 set(NETDATA_COMMON_LIBRARIES ${NETDATA_COMMON_LIBRARIES} ${OPENSSL_LIBRARIES})
131 set(NETDATA_COMMON_INCLUDE_DIRS ${NETDATA_COMMON_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS})
132
133 -# -----------------------------------------------------------------------------
134 -# JSON-C used to health
135 -
136 -pkg_check_modules(JSON REQUIRED json-c)
137 -set(NETDATA_COMMON_CFLAGS ${NETDATA_COMMON_CFLAGS} ${JSONC_CFLAGS_OTHER})
138 -set(NETDATA_COMMON_LIBRARIES ${NETDATA_COMMON_LIBRARIES} ${JSON_LIBRARIES})
139 -set(NETDATA_COMMON_INCLUDE_DIRS ${NETDATA_COMMON_INCLUDE_DIRS} ${JSON_INCLUDE_DIRS})
140 -
133 # -----------------------------------------------------------------------------
134 # Detect libcap
135
@@ -313,15 +305,8 @@ set(LIBNETDATA_FILES
305 libnetdata/threads/threads.h
306 libnetdata/url/url.c
307 libnetdata/url/url.h
316 - libnetdata/health/health.c
317 - libnetdata/health/health.h
308 libnetdata/socket/security.c
319 - libnetdata/socket/security.h
320 - libnetdata/json/json.c
321 - libnetdata/json/json.h
322 - libnetdata/json/jsmn.c
323 - libnetdata/json/jsmn.h
324 - )
309 + libnetdata/socket/security.h)
310
311 add_library(libnetdata OBJECT ${LIBNETDATA_FILES})
312
Makefile.am
+3 -9
@@ -159,14 +159,8 @@ LIBNETDATA_FILES = \
159 libnetdata/storage_number/storage_number.h \
160 libnetdata/threads/threads.c \
161 libnetdata/threads/threads.h \
162 - libnetdata/url/url.c \
163 - libnetdata/url/url.h \
164 - libnetdata/json/jsmn.h \
165 - libnetdata/json/jsmn.c \
166 - libnetdata/json/json.h \
167 - libnetdata/json/json.c \
168 - libnetdata/health/health.c \
169 - libnetdata/health/health.h \
162 + libnetdata/url/url.c \
163 + libnetdata/url/url.h \
164 $(NULL)
165
166 APPS_PLUGIN_FILES = \
@@ -512,12 +506,12 @@ endif
506 NETDATA_COMMON_LIBS = \
507 $(OPTIONAL_MATH_LIBS) \
508 $(OPTIONAL_ZLIB_LIBS) \
509 + $(OPTIONAL_SSL_LIBS) \
510 $(OPTIONAL_UUID_LIBS) \
511 $(OPTIONAL_UV_LIBS) \
512 $(OPTIONAL_LZ4_LIBS) \
513 $(OPTIONAL_JUDY_LIBS) \
514 $(OPTIONAL_SSL_LIBS) \
520 - $(OPTIONAL_JSONC_LIBS) \
515 $(NULL)
516
517 sbin_PROGRAMS += netdata
configure.ac
-39
@@ -142,12 +142,6 @@ AC_ARG_ENABLE(
142 ,
143 [enable_https="detect"]
144 )
145 -AC_ARG_ENABLE(
146 - [jsonc],
147 - [AS_HELP_STRING([--enable-jsonc], [Enable JSON-C support @<:@default autodetect@:>@])],
148 - ,
149 - [enable_jsonc="detect"]
150 -)
145 AC_ARG_ENABLE(
146 [dbengine],
147 [AS_HELP_STRING([--disable-dbengine], [disable netdata dbengine @<:@default autodetect@:>@])],
@@ -353,20 +347,6 @@ AC_CHECK_LIB(
347 OPTIONAL_SSL_CFLAGS="${SSL_CFLAGS}"
348 OPTIONAL_SSL_LIBS="${SSL_LIBS}"
349
356 -# -----------------------------------------------------------------------------
357 -# JSON-C library
358 -
359 -PKG_CHECK_MODULES([JSON],[json-c],AC_CHECK_LIB(
360 - [json-c],
361 - [json_object_get_type],
362 - [JSONC_LIBS="-ljson-c"]),AC_CHECK_LIB(
363 - [json],
364 - [json_object_get_type],
365 - [JSONC_LIBS="-ljson"])
366 - )
367 -
368 -OPTIONAL_JSONC_LIBS="${JSONC_LIBS}"
369 -
350 # -----------------------------------------------------------------------------
351 # DB engine and HTTPS
352 test "${enable_dbengine}" = "yes" -a -z "${UV_LIBS}" && \
@@ -401,22 +381,6 @@ fi
381 AC_MSG_RESULT([${enable_https}])
382 AM_CONDITIONAL([ENABLE_HTTPS], [test "${enable_https}" = "yes"])
383
404 -# -----------------------------------------------------------------------------
405 -# JSON-C
406 -test "${enable_jsonc}" = "yes" -a -z "${JSONC_LIBS}" && \
407 - AC_MSG_ERROR([JSON-C required but not found. Try installing 'libjson-c-dev' or 'json-c'.])
408 -
409 -AC_MSG_CHECKING([if json-c should be used])
410 -if test "${enable_jsonc}" != "no" -a "${JSONC_LIBS}"; then
411 - enable_jsonc="yes"
412 - AC_DEFINE([ENABLE_JSONC], [1], [netdata json-c usability])
413 -else
414 - enable_jsonc="no"
415 -fi
416 -AC_MSG_RESULT([${enable_jsonc}])
417 -AM_CONDITIONAL([ENABLE_JSONC], [test "${enable_jsonc}" = "yes"])
418 -
419 -
384 # -----------------------------------------------------------------------------
385 # compiler options
386
@@ -1011,7 +975,6 @@ AC_SUBST([OPTIONAL_UV_LIBS])
975 AC_SUBST([OPTIONAL_LZ4_LIBS])
976 AC_SUBST([OPTIONAL_JUDY_LIBS])
977 AC_SUBST([OPTIONAL_SSL_LIBS])
1014 -AC_SUBST([OPTIONAL_JSONC_LIBS])
978 AC_SUBST([OPTIONAL_NFACCT_CFLAGS])
979 AC_SUBST([OPTIONAL_NFACCT_LIBS])
980 AC_SUBST([OPTIONAL_ZLIB_CFLAGS])
@@ -1078,8 +1041,6 @@ AC_CONFIG_FILES([
1041 libnetdata/config/Makefile
1042 libnetdata/dictionary/Makefile
1043 libnetdata/eval/Makefile
1081 - libnetdata/json/Makefile
1082 - libnetdata/health/Makefile
1044 libnetdata/locks/Makefile
1045 libnetdata/log/Makefile
1046 libnetdata/popen/Makefile
health/health.c
+5 -96
@@ -1,6 +1,5 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 -#include <libnetdata/json/json.h>
3 #include "health.h"
4
5 struct health_cmdapi_thread_status {
@@ -14,79 +13,18 @@ unsigned int default_health_enabled = 1;
13 // ----------------------------------------------------------------------------
14 // health initialization
15
17 -/**
18 - * User Config directory
19 - *
20 - * Get the config directory for health and return it.
21 - *
22 - * @return a pointer to the user config directory
23 - */
16 inline char *health_user_config_dir(void) {
17 char buffer[FILENAME_MAX + 1];
18 snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_user_config_dir);
19 return config_get(CONFIG_SECTION_HEALTH, "health configuration directory", buffer);
20 }
21
30 -/**
31 - * Stock Config Directory
32 - *
33 - * Get the Stock config directory and return it.
34 - *
35 - * @return a pointer to the stock config directory.
36 - */
22 inline char *health_stock_config_dir(void) {
23 char buffer[FILENAME_MAX + 1];
24 snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_stock_config_dir);
25 return config_get(CONFIG_SECTION_HEALTH, "stock health configuration directory", buffer);
26 }
27
43 -
44 -/**
45 - * Silencers init
46 - *
47 - * Function used to initialize the silencer structure.
48 - */
49 -void health_silencers_init(void) {
50 - silencers = mallocz(sizeof(SILENCERS));
51 - silencers->all_alarms=0;
52 - silencers->stype=STYPE_NONE;
53 - silencers->silencers=NULL;
54 -
55 - char filename[FILENAME_MAX + 1];
56 - snprintfz(filename, FILENAME_MAX, "%s/health.silencers.json", netdata_configured_varlib_dir);
57 - silencers_filename = config_get(CONFIG_SECTION_HEALTH, "silencers file", filename);
58 -
59 - struct stat statbuf;
60 - if (!stat(silencers_filename,&statbuf)) {
61 - off_t length = statbuf.st_size;
62 - if (length && length < HEALTH_SILENCERS_MAX_FILE_LEN) {
63 - FILE *fd = fopen(silencers_filename, "r");
64 - if (fd) {
65 - char *str = mallocz((length+1)* sizeof(char));
66 - if(str) {
67 - fread(str, sizeof(char), length, fd);
68 - str[length] = 0x00;
69 - json_parse(str, NULL, health_silencers_json_read_callback);
70 - freez(str);
71 - info("Parsed health silencers file %s", silencers_filename);
72 - }
73 - fclose(fd);
74 - } else {
75 - error("Cannot open the file %s",silencers_filename);
76 - }
77 - } else {
78 - error("Health silencers file %s has the size %ld that is out of range[ 1 , %d ]. Aborting read.", silencers_filename, length, HEALTH_SILENCERS_MAX_FILE_LEN);
79 - }
80 - } else {
81 - error("Cannot open the file %s",silencers_filename);
82 - }
83 -}
84 -
85 -/**
86 - * Health Init
87 - *
88 - * Initialize the health thread.
89 - */
28 void health_init(void) {
29 debug(D_HEALTH, "Health configuration initializing");
30
@@ -94,20 +32,11 @@ void health_init(void) {
32 debug(D_HEALTH, "Health is disabled.");
33 return;
34 }
97 -
98 - health_silencers_init();
35 }
36
37 // ----------------------------------------------------------------------------
38 // re-load health configuration
39
104 -/**
105 - * Reload host
106 - *
107 - * Reload configuration for a specific host.
108 - *
109 - * @param host the structure of the host that the function will reload the configuration.
110 - */
40 void health_reload_host(RRDHOST *host) {
41 if(unlikely(!host->health_enabled))
42 return;
@@ -155,11 +84,6 @@ void health_reload_host(RRDHOST *host) {
84 rrdhost_unlock(host);
85 }
86
158 -/**
159 - * Reload
160 - *
161 - * Reload the host configuration for all hosts.
162 - */
87 void health_reload(void) {
88
89 rrd_rdlock();
@@ -501,16 +425,6 @@ SILENCE_TYPE check_silenced(RRDCALC *rc, char* host, SILENCERS *silencers) {
425 return STYPE_NONE;
426 }
427
504 -/**
505 - * Update Disabled Silenced
506 - *
507 - * Update the variable rrdcalc_flags of the structure RRDCALC according with the values of the host structure
508 - *
509 - * @param host structure that contains information about the host monitored.
510 - * @param rc structure with information about the alarm
511 - *
512 - * @return It returns 1 case rrdcalc_flags is DISABLED or 0 otherwise
513 - */
428 int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) {
429 uint32_t rrdcalc_flags_old = rc->rrdcalc_flags;
430 // Clear the flags
@@ -540,15 +454,6 @@ int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) {
454 return 0;
455 }
456
543 -/**
544 - * Health Main
545 - *
546 - * The main thread of the health system. In this function all the alarms will be processed.
547 - *
548 - * @param ptr is a pointer to the netdata_static_thread structure.
549 - *
550 - * @return It always returns NULL
551 - */
457 void *health_main(void *ptr) {
458 netdata_thread_cleanup_push(health_main_cleanup, ptr);
459
@@ -560,6 +465,11 @@ void *health_main(void *ptr) {
465
466 unsigned int loop = 0;
467
468 + silencers = mallocz(sizeof(SILENCERS));
469 + silencers->all_alarms=0;
470 + silencers->stype=STYPE_NONE;
471 + silencers->silencers=NULL;
472 +
473 while(!netdata_exit) {
474 loop++;
475 debug(D_HEALTH, "Health monitoring iteration no %u started", loop);
@@ -613,7 +523,6 @@ void *health_main(void *ptr) {
523 // the first loop is to lookup values from the db
524 for (rc = host->alarms; rc; rc = rc->next) {
525
616 - //case it is disabled I will get the next rc
526 if (update_disabled_silenced(host, rc))
527 continue;
528
health/health.h
+40 -4
@@ -35,9 +35,16 @@ extern unsigned int default_health_enabled;
35 #define HEALTH_LISTEN_BACKLOG 4096
36 #endif
37
38 -
38 +#define HEALTH_ALARM_KEY "alarm"
39 +#define HEALTH_TEMPLATE_KEY "template"
40 #define HEALTH_ON_KEY "on"
40 -
41 +#define HEALTH_CONTEXT_KEY "context"
42 +#define HEALTH_CHART_KEY "chart"
43 +#define HEALTH_HOST_KEY "hosts"
44 +#define HEALTH_OS_KEY "os"
45 +#define HEALTH_FAMILIES_KEY "families"
46 +#define HEALTH_LOOKUP_KEY "lookup"
47 +#define HEALTH_CALC_KEY "calc"
48 #define HEALTH_EVERY_KEY "every"
49 #define HEALTH_GREEN_KEY "green"
50 #define HEALTH_RED_KEY "red"
@@ -50,9 +57,38 @@ extern unsigned int default_health_enabled;
57 #define HEALTH_DELAY_KEY "delay"
58 #define HEALTH_OPTIONS_KEY "options"
59
53 -#define HEALTH_SILENCERS_MAX_FILE_LEN 10000
60 +typedef struct silencer {
61 + char *alarms;
62 + SIMPLE_PATTERN *alarms_pattern;
63 +
64 + char *hosts;
65 + SIMPLE_PATTERN *hosts_pattern;
66 +
67 + char *contexts;
68 + SIMPLE_PATTERN *contexts_pattern;
69 +
70 + char *charts;
71 + SIMPLE_PATTERN *charts_pattern;
72 +
73 + char *families;
74 + SIMPLE_PATTERN *families_pattern;
75 +
76 + struct silencer *next;
77 +} SILENCER;
78 +
79 +typedef enum silence_type {
80 + STYPE_NONE,
81 + STYPE_DISABLE_ALARMS,
82 + STYPE_SILENCE_NOTIFICATIONS
83 +} SILENCE_TYPE;
84 +
85 +typedef struct silencers {
86 + int all_alarms;
87 + SILENCE_TYPE stype;
88 + SILENCER *silencers;
89 +} SILENCERS;
90
55 -char *silencers_filename;
91 +SILENCERS *silencers;
92
93 extern void health_init(void);
94 extern void *health_main(void *ptr);
health/health_config.c
+1 -1
@@ -481,7 +481,7 @@ static int health_readfile(const char *filename, void *data) {
481 if(append < HEALTH_CONF_MAX_LINE)
482 continue;
483 else {
484 - error("Health configuration has too long multi-line at line %zu of file '%s'.", line, filename);
484 + error("Health configuration has too long muli-line at line %zu of file '%s'.", line, filename);
485 }
486 }
487 append = 0;
libnetdata/Makefile.am
-2
@@ -21,8 +21,6 @@ SUBDIRS = \
21 storage_number \
22 threads \
23 url \
24 - json \
25 - health \
24 $(NULL)
25
26 dist_noinst_DATA = \
libnetdata/health/Makefile.am deleted
-8
@@ -1,8 +0,0 @@
1 -# SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -AUTOMAKE_OPTIONS = subdir-objects
4 -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5 -
6 -
7 -dist_noinst_DATA = \
8 - $(NULL)
libnetdata/health/health.c deleted
-154
@@ -1,154 +0,0 @@
1 -#include "health.h"
2 -
3 -/**
4 - * Create Silencer
5 - *
6 - * Allocate a new silencer to Netdata.
7 - *
8 - * @return It returns the address off the silencer on success and NULL otherwise
9 - */
10 -SILENCER *create_silencer(void) {
11 - SILENCER *t = callocz(1, sizeof(SILENCER));
12 - debug(D_HEALTH, "HEALTH command API: Created empty silencer");
13 -
14 - return t;
15 -}
16 -
17 -/**
18 - * Health Silencers add
19 - *
20 - * Add more one silencer to the list of silenecers.
21 - *
22 - * @param silencer
23 - */
24 -void health_silencers_add(SILENCER *silencer) {
25 - // Add the created instance to the linked list in silencers
26 - silencer->next = silencers->silencers;
27 - silencers->silencers = silencer;
28 - debug(D_HEALTH, "HEALTH command API: Added silencer %s:%s:%s:%s:%s", silencer->alarms,
29 - silencer->charts, silencer->contexts, silencer->hosts, silencer->families
30 - );
31 -}
32 -
33 -/**
34 - * Silencers Add Parameter
35 - *
36 - * Create a new silencer and adjust the variables
37 - *
38 - * @param silencer a pointer to the silencer that will be adjusted
39 - * @param key the key value sent by client
40 - * @param value the value sent to the key
41 - *
42 - * @return It returns the silencer configured on success and NULL otherwise
43 - */
44 -SILENCER *health_silencers_addparam(SILENCER *silencer, char *key, char *value) {
45 - static uint32_t
46 - hash_alarm = 0,
47 - hash_template = 0,
48 - hash_chart = 0,
49 - hash_context = 0,
50 - hash_host = 0,
51 - hash_families = 0;
52 -
53 - if (unlikely(!hash_alarm)) {
54 - hash_alarm = simple_uhash(HEALTH_ALARM_KEY);
55 - hash_template = simple_uhash(HEALTH_TEMPLATE_KEY);
56 - hash_chart = simple_uhash(HEALTH_CHART_KEY);
57 - hash_context = simple_uhash(HEALTH_CONTEXT_KEY);
58 - hash_host = simple_uhash(HEALTH_HOST_KEY);
59 - hash_families = simple_uhash(HEALTH_FAMILIES_KEY);
60 - }
61 -
62 - uint32_t hash = simple_uhash(key);
63 - if (unlikely(silencer == NULL)) {
64 - if (
65 - (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) ||
66 - (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) ||
67 - (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) ||
68 - (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) ||
69 - (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) ||
70 - (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY))
71 - ) {
72 - silencer = create_silencer();
73 - if(!silencer) {
74 - error("Cannot add a new silencer to Netdata");
75 - return NULL;
76 - }
77 - }
78 - }
79 -
80 - if (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
81 - silencer->alarms = strdupz(value);
82 - silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT);
83 - } else if (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) {
84 - silencer->charts = strdupz(value);
85 - silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT);
86 - } else if (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) {
87 - silencer->contexts = strdupz(value);
88 - silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT);
89 - } else if (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) {
90 - silencer->hosts = strdupz(value);
91 - silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT);
92 - } else if (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
93 - silencer->families = strdupz(value);
94 - silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT);
95 - }
96 -
97 - return silencer;
98 -}
99 -
100 -/**
101 - * JSON Read Callback
102 - *
103 - * Callback called by netdata to create the silencer.
104 - *
105 - * @param e the main json structure
106 - *
107 - * @return It always return 0.
108 - */
109 -int health_silencers_json_read_callback(JSON_ENTRY *e)
110 -{
111 - switch(e->type) {
112 - case JSON_OBJECT:
113 -#ifndef ENABLE_JSONC
114 - e->callback_function = health_silencers_json_read_callback;
115 - if(e->name && strcmp(e->name,"")) {
116 - // init silencer
117 - debug(D_HEALTH, "JSON: Got object with a name, initializing new silencer for %s",e->name);
118 -#endif
119 - e->callback_data = create_silencer();
120 - if(e->callback_data) {
121 - health_silencers_add(e->callback_data);
122 - }
123 -#ifndef ENABLE_JSONC
124 - }
125 -#endif
126 - break;
127 -
128 - case JSON_ARRAY:
129 - e->callback_function = health_silencers_json_read_callback;
130 - break;
131 -
132 - case JSON_STRING:
133 - if(!strcmp(e->name,"type")) {
134 - debug(D_HEALTH, "JSON: Processing type=%s",e->data.string);
135 - if (!strcmp(e->data.string,"SILENCE")) silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
136 - else if (!strcmp(e->data.string,"DISABLE")) silencers->stype = STYPE_DISABLE_ALARMS;
137 - } else {
138 - debug(D_HEALTH, "JSON: Adding %s=%s", e->name, e->data.string);
139 - health_silencers_addparam(e->callback_data, e->name, e->data.string);
140 - }
141 - break;
142 -
143 - case JSON_BOOLEAN:
144 - debug(D_HEALTH, "JSON: Processing all_alarms");
145 - silencers->all_alarms=e->data.boolean?1:0;
146 - break;
147 -
148 - case JSON_NUMBER:
149 - case JSON_NULL:
150 - break;
151 - }
152 -
153 - return 0;
154 -}
libnetdata/health/health.h deleted
-54
@@ -1,54 +0,0 @@
1 -#ifndef NETDATA_HEALTH_LIB
2 -# define NETDATA_HEALTH_LIB 1
3 -
4 -# include "../libnetdata.h"
5 -
6 -#define HEALTH_ALARM_KEY "alarm"
7 -#define HEALTH_TEMPLATE_KEY "template"
8 -#define HEALTH_CONTEXT_KEY "context"
9 -#define HEALTH_CHART_KEY "chart"
10 -#define HEALTH_HOST_KEY "hosts"
11 -#define HEALTH_OS_KEY "os"
12 -#define HEALTH_FAMILIES_KEY "families"
13 -#define HEALTH_LOOKUP_KEY "lookup"
14 -#define HEALTH_CALC_KEY "calc"
15 -
16 -typedef struct silencer {
17 - char *alarms;
18 - SIMPLE_PATTERN *alarms_pattern;
19 -
20 - char *hosts;
21 - SIMPLE_PATTERN *hosts_pattern;
22 -
23 - char *contexts;
24 - SIMPLE_PATTERN *contexts_pattern;
25 -
26 - char *charts;
27 - SIMPLE_PATTERN *charts_pattern;
28 -
29 - char *families;
30 - SIMPLE_PATTERN *families_pattern;
31 -
32 - struct silencer *next;
33 -} SILENCER;
34 -
35 -typedef enum silence_type {
36 - STYPE_NONE,
37 - STYPE_DISABLE_ALARMS,
38 - STYPE_SILENCE_NOTIFICATIONS
39 -} SILENCE_TYPE;
40 -
41 -typedef struct silencers {
42 - int all_alarms;
43 - SILENCE_TYPE stype;
44 - SILENCER *silencers;
45 -} SILENCERS;
46 -
47 -SILENCERS *silencers;
48 -
49 -extern SILENCER *create_silencer(void);
50 -extern int health_silencers_json_read_callback(JSON_ENTRY *e);
51 -extern void health_silencers_add(SILENCER *silencer);
52 -extern SILENCER * health_silencers_addparam(SILENCER *silencer, char *key, char *value);
53 -
54 -#endif
libnetdata/json/Makefile.am deleted
-9
@@ -1,9 +0,0 @@
1 -# SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -AUTOMAKE_OPTIONS = subdir-objects
4 -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5 -
6 -
7 -dist_noinst_DATA = \
8 - README.md \
9 - $(NULL)
libnetdata/json/README.md deleted
-5
@@ -1,5 +0,0 @@
1 -# json
2 -
3 -`json` contains a parser for json strings, based on `jsmn` (https://github.com/zserge/jsmn), but case you have installed the JSON-C library, the installation script will prefer it, you can also force its use with `--enable-jsonc` in the compilation time.
4 -
5 -[![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Flibnetdata%2Fjson%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)]()
libnetdata/json/jsmn.c deleted
-326
@@ -1,326 +0,0 @@
1 -#include <stdlib.h>
2 -
3 -#include "jsmn.h"
4 -
5 -/**
6 - * Alloc token
7 - *
8 - * Allocates a fresh unused token from the token pull.
9 - *
10 - * @param parser the controller
11 - * @param tokens the tokens I am working
12 - * @param num_tokens the number total of tokens.
13 - *
14 - * @return it returns the next token to work.
15 - */
16 -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
17 - jsmntok_t *tokens, size_t num_tokens) {
18 - jsmntok_t *tok;
19 - if (parser->toknext >= num_tokens) {
20 - return NULL;
21 - }
22 - tok = &tokens[parser->toknext++];
23 - tok->start = tok->end = -1;
24 - tok->size = 0;
25 -#ifdef JSMN_PARENT_LINKS
26 - tok->parent = -1;
27 -#endif
28 - return tok;
29 -}
30 -
31 -/**
32 - * Fill Token
33 - *
34 - * Fills token type and boundaries.
35 - *
36 - * @param token the structure to set the values
37 - * @param type is the token type
38 - * @param start is the first position of the value
39 - * @param end is the end of the value
40 - */
41 -static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
42 - int start, int end) {
43 - token->type = type;
44 - token->start = start;
45 - token->end = end;
46 - token->size = 0;
47 -}
48 -
49 -/**
50 - * Parse primitive
51 - *
52 - * Fills next available token with JSON primitive.
53 - *
54 - * @param parser is the control structure
55 - * @param js is the json string
56 - * @param type is the token type
57 - */
58 -static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
59 - size_t len, jsmntok_t *tokens, size_t num_tokens) {
60 - jsmntok_t *token;
61 - int start;
62 -
63 - start = parser->pos;
64 -
65 - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
66 - switch (js[parser->pos]) {
67 -#ifndef JSMN_STRICT
68 - /* In strict mode primitive must be followed by "," or "}" or "]" */
69 - case ':':
70 -#endif
71 - case '\t' : case '\r' : case '\n' : case ' ' :
72 - case ',' : case ']' : case '}' :
73 - goto found;
74 - }
75 - if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
76 - parser->pos = start;
77 - return JSMN_ERROR_INVAL;
78 - }
79 - }
80 -#ifdef JSMN_STRICT
81 - /* In strict mode primitive must be followed by a comma/object/array */
82 - parser->pos = start;
83 - return JSMN_ERROR_PART;
84 -#endif
85 -
86 - found:
87 - if (tokens == NULL) {
88 - parser->pos--;
89 - return 0;
90 - }
91 - token = jsmn_alloc_token(parser, tokens, num_tokens);
92 - if (token == NULL) {
93 - parser->pos = start;
94 - return JSMN_ERROR_NOMEM;
95 - }
96 - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
97 -#ifdef JSMN_PARENT_LINKS
98 - token->parent = parser->toksuper;
99 -#endif
100 - parser->pos--;
101 - return 0;
102 -}
103 -
104 -/**
105 - * Parse string
106 - *
107 - * Fills next token with JSON string.
108 - *
109 - * @param parser is the control structure
110 - * @param js is the json string
111 - * @param len is the js length
112 - * @param tokens is structure with the tokens mapped.
113 - * @param num_tokens is the total number of tokens
114 - *
115 - * @return It returns 0 on success and another integer otherwise
116 - */
117 -static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
118 - size_t len, jsmntok_t *tokens, size_t num_tokens) {
119 - jsmntok_t *token;
120 -
121 - int start = parser->pos;
122 -
123 - parser->pos++;
124 -
125 - /* Skip starting quote */
126 - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
127 - char c = js[parser->pos];
128 -
129 - /* Quote: end of string */
130 - if (c == '\"') {
131 - if (tokens == NULL) {
132 - return 0;
133 - }
134 - token = jsmn_alloc_token(parser, tokens, num_tokens);
135 - if (token == NULL) {
136 - parser->pos = start;
137 - return JSMN_ERROR_NOMEM;
138 - }
139 - jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
140 -#ifdef JSMN_PARENT_LINKS
141 - token->parent = parser->toksuper;
142 -#endif
143 - return 0;
144 - }
145 -
146 - /* Backslash: Quoted symbol expected */
147 - if (c == '\\') {
148 - parser->pos++;
149 - switch (js[parser->pos]) {
150 - /* Allowed escaped symbols */
151 - case '\"': case '/' : case '\\' : case 'b' :
152 - case 'f' : case 'r' : case 'n' : case 't' :
153 - break;
154 - /* Allows escaped symbol \uXXXX */
155 - case 'u':
156 - parser->pos++;
157 - int i = 0;
158 - for(; i < 4 && js[parser->pos] != '\0'; i++) {
159 - /* If it isn't a hex character we have an error */
160 - if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
161 - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
162 - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
163 - parser->pos = start;
164 - return JSMN_ERROR_INVAL;
165 - }
166 - parser->pos++;
167 - }
168 - parser->pos--;
169 - break;
170 - /* Unexpected symbol */
171 - default:
172 - parser->pos = start;
173 - return JSMN_ERROR_INVAL;
174 - }
175 - }
176 - }
177 - parser->pos = start;
178 - return JSMN_ERROR_PART;
179 -}
180 -
181 -/**
182 - * JSMN Parse
183 - *
184 - * Parse JSON string and fill tokens.
185 - *
186 - * @param parser the auxiliar vector used to parser
187 - * @param js the string to parse
188 - * @param len the string length
189 - * @param tokens the place to map the tokens
190 - * @param num_tokens the number of tokens present in the tokens structure.
191 - *
192 - * @return It returns the number of tokens present in the string on success or a negative number otherwise
193 - */
194 -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
195 - jsmntok_t *tokens, unsigned int num_tokens) {
196 - jsmnerr_t r;
197 - int i;
198 - jsmntok_t *token;
199 - int count = 0;
200 -
201 - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
202 - char c;
203 - jsmntype_t type;
204 -
205 - c = js[parser->pos];
206 - switch (c) {
207 - case '{': case '[':
208 - count++;
209 - if (tokens == NULL) {
210 - break;
211 - }
212 - token = jsmn_alloc_token(parser, tokens, num_tokens);
213 - if (token == NULL)
214 - return JSMN_ERROR_NOMEM;
215 - if (parser->toksuper != -1) {
216 - tokens[parser->toksuper].size++;
217 -#ifdef JSMN_PARENT_LINKS
218 - token->parent = parser->toksuper;
219 -#endif
220 - }
221 - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
222 - token->start = parser->pos;
223 - parser->toksuper = parser->toknext - 1;
224 - break;
225 - case '}': case ']':
226 - if (tokens == NULL)
227 - break;
228 - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
229 -#ifdef JSMN_PARENT_LINKS
230 - if (parser->toknext < 1) {
231 - return JSMN_ERROR_INVAL;
232 - }
233 - token = &tokens[parser->toknext - 1];
234 - for (;;) {
235 - if (token->start != -1 && token->end == -1) {
236 - if (token->type != type) {
237 - return JSMN_ERROR_INVAL;
238 - }
239 - token->end = parser->pos + 1;
240 - parser->toksuper = token->parent;
241 - break;
242 - }
243 - if (token->parent == -1) {
244 - break;
245 - }
246 - token = &tokens[token->parent];
247 - }
248 -#else
249 - for (i = parser->toknext - 1; i >= 0; i--) {
250 - token = &tokens[i];
251 - if (token->start != -1 && token->end == -1) {
252 - if (token->type != type) {
253 - return JSMN_ERROR_INVAL;
254 - }
255 - parser->toksuper = -1;
256 - token->end = parser->pos + 1;
257 - break;
258 - }
259 - }
260 - /* Error if unmatched closing bracket */
261 - if (i == -1) return JSMN_ERROR_INVAL;
262 - for (; i >= 0; i--) {
263 - token = &tokens[i];
264 - if (token->start != -1 && token->end == -1) {
265 - parser->toksuper = i;
266 - break;
267 - }
268 - }
269 -#endif
270 - break;
271 - case '\"':
272 - r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
273 - if (r < 0) return r;
274 - count++;
275 - if (parser->toksuper != -1 && tokens != NULL)
276 - tokens[parser->toksuper].size++;
277 - break;
278 - case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
279 - break;
280 -#ifdef JSMN_STRICT
281 - /* In strict mode primitives are: numbers and booleans */
282 - case '-': case '0': case '1' : case '2': case '3' : case '4':
283 - case '5': case '6': case '7' : case '8': case '9':
284 - case 't': case 'f': case 'n' :
285 -#else
286 - /* In non-strict mode every unquoted value is a primitive */
287 - default:
288 -#endif
289 - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
290 - if (r < 0) return r;
291 - count++;
292 - if (parser->toksuper != -1 && tokens != NULL)
293 - tokens[parser->toksuper].size++;
294 - break;
295 -
296 -#ifdef JSMN_STRICT
297 - /* Unexpected char in strict mode */
298 - default:
299 - return JSMN_ERROR_INVAL;
300 -#endif
301 - }
302 - }
303 -
304 - for (i = parser->toknext - 1; i >= 0; i--) {
305 - /* Unmatched opened object or array */
306 - if (tokens[i].start != -1 && tokens[i].end == -1) {
307 - return JSMN_ERROR_PART;
308 - }
309 - }
310 -
311 - return count;
312 -}
313 -
314 -/**
315 - * JSMN Init
316 - *
317 - * Creates a new parser based over a given buffer with an array of tokens
318 - * available.
319 - *
320 - * @param parser is the structure with values to reset
321 - */
322 -void jsmn_init(jsmn_parser *parser) {
323 - parser->pos = 0;
324 - parser->toknext = 0;
325 - parser->toksuper = -1;
326 -}
\ No newline at end of file
libnetdata/json/jsmn.h deleted
-75
@@ -1,75 +0,0 @@
1 -#ifndef __JSMN_H_
2 -#define __JSMN_H_
3 -
4 -#ifdef __cplusplus
5 -extern "C" {
6 -#endif
7 -
8 -#include <stddef.h>
9 -/**
10 - * JSON type identifier. Basic types are:
11 - * o Object
12 - * o Array
13 - * o String
14 - * o Other primitive: number, boolean (true/false) or null
15 - */
16 -typedef enum {
17 - JSMN_PRIMITIVE = 0,
18 - JSMN_OBJECT = 1,
19 - JSMN_ARRAY = 2,
20 - JSMN_STRING = 3
21 -} jsmntype_t;
22 -
23 -typedef enum {
24 - /* Not enough tokens were provided */
25 - JSMN_ERROR_NOMEM = -1,
26 - /* Invalid character inside JSON string */
27 - JSMN_ERROR_INVAL = -2,
28 - /* The string is not a full JSON packet, more bytes expected */
29 - JSMN_ERROR_PART = -3,
30 -} jsmnerr_t;
31 -
32 -/**
33 - * JSON token description.
34 - *
35 - * @param type type (object, array, string etc.)
36 - * @param start start position in JSON data string
37 - * @param end end position in JSON data string
38 - */
39 -typedef struct {
40 - jsmntype_t type;
41 - int start;
42 - int end;
43 - int size;
44 -#ifdef JSMN_PARENT_LINKS
45 - int parent;
46 -#endif
47 -} jsmntok_t;
48 -
49 -/**
50 - * JSON parser. Contains an array of token blocks available. Also stores
51 - * the string being parsed now and current position in that string
52 - */
53 -typedef struct {
54 - unsigned int pos; /* offset in the JSON string */
55 - unsigned int toknext; /* next token to allocate */
56 - int toksuper; /* superior token node, e.g parent object or array */
57 -} jsmn_parser;
58 -
59 -/**
60 - * Create JSON parser over an array of tokens
61 - */
62 -void jsmn_init(jsmn_parser *parser);
63 -
64 -/**
65 - * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
66 - * a single JSON object.
67 - */
68 -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
69 - jsmntok_t *tokens, unsigned int num_tokens);
70 -
71 -#ifdef __cplusplus
72 -}
73 -#endif
74 -
75 -#endif /* __JSMN_H_ */
\ No newline at end of file
libnetdata/json/json.c deleted
-546
@@ -1,546 +0,0 @@
1 -#include "jsmn.h"
2 -#include "../libnetdata.h"
3 -#include "json.h"
4 -#include "libnetdata/libnetdata.h"
5 -#include "../../health/health.h"
6 -
7 -#define JSON_TOKENS 1024
8 -
9 -int json_tokens = JSON_TOKENS;
10 -
11 -/**
12 - * Json Tokenise
13 - *
14 - * Map the string given inside tokens.
15 - *
16 - * @param js is the string used to create the tokens
17 - * @param len is the string length
18 - * @param count the number of tokens present in the string
19 - *
20 - * @return it returns the json parsed in tokens
21 - */
22 -#ifdef ENABLE_JSONC
23 -json_object *json_tokenise(char *js) {
24 - if(!js) {
25 - error("JSON: json string is empty.");
26 - return NULL;
27 - }
28 -
29 - json_object *token = json_tokener_parse(js);
30 - if(!token) {
31 - error("JSON: Invalid json string.");
32 - return NULL;
33 - }
34 -
35 - return token;
36 -}
37 -#else
38 -jsmntok_t *json_tokenise(char *js, size_t len, size_t *count)
39 -{
40 - int n = json_tokens;
41 - if(!js || !len) {
42 - error("JSON: json string is empty.");
43 - return NULL;
44 - }
45 -
46 - jsmn_parser parser;
47 - jsmn_init(&parser);
48 -
49 - jsmntok_t *tokens = mallocz(sizeof(jsmntok_t) * n);
50 - if(!tokens) return NULL;
51 -
52 - int ret = jsmn_parse(&parser, js, len, tokens, n);
53 - while (ret == JSMN_ERROR_NOMEM) {
54 - n *= 2;
55 - jsmntok_t *new = reallocz(tokens, sizeof(jsmntok_t) * n);
56 - if(!new) {
57 - freez(tokens);
58 - return NULL;
59 - }
60 - tokens = new;
61 - ret = jsmn_parse(&parser, js, len, tokens, n);
62 - }
63 -
64 - if (ret == JSMN_ERROR_INVAL) {
65 - error("JSON: Invalid json string.");
66 - freez(tokens);
67 - return NULL;
68 - }
69 - else if (ret == JSMN_ERROR_PART) {
70 - error("JSON: Truncated JSON string.");
71 - freez(tokens);
72 - return NULL;
73 - }
74 -
75 - if(count) *count = (size_t)ret;
76 -
77 - if(json_tokens < n) json_tokens = n;
78 - return tokens;
79 -}
80 -#endif
81 -
82 -/**
83 - * Callback Print
84 - *
85 - * Set callback print case necesary and wrinte an information inside a buffer to write in the log.
86 - *
87 - * @param e a pointer for a structure that has the complete information about json structure.
88 - *
89 - * @return It always return 0
90 - */
91 -int json_callback_print(JSON_ENTRY *e)
92 -{
93 - BUFFER *wb=buffer_create(300);
94 -
95 - buffer_sprintf(wb,"%s = ", e->name);
96 - char txt[50];
97 - switch(e->type) {
98 - case JSON_OBJECT:
99 - e->callback_function = json_callback_print;
100 - buffer_strcat(wb,"OBJECT");
101 - break;
102 -
103 - case JSON_ARRAY:
104 - e->callback_function = json_callback_print;
105 - sprintf(txt,"ARRAY[%lu]", e->data.items);
106 - buffer_strcat(wb, txt);
107 - break;
108 -
109 - case JSON_STRING:
110 - buffer_strcat(wb, e->data.string);
111 - break;
112 -
113 - case JSON_NUMBER:
114 - sprintf(txt,"%Lf", e->data.number);
115 - buffer_strcat(wb,txt);
116 -
117 - break;
118 -
119 - case JSON_BOOLEAN:
120 - buffer_strcat(wb, e->data.boolean?"TRUE":"FALSE");
121 - break;
122 -
123 - case JSON_NULL:
124 - buffer_strcat(wb,"NULL");
125 - break;
126 - }
127 - info("JSON: %s", buffer_tostring(wb));
128 - buffer_free(wb);
129 - return 0;
130 -}
131 -
132 -/**
133 - * JSONC Set String
134 - *
135 - * Set the string value of the structure JSON_ENTRY.
136 - *
137 - * @param e the output structure
138 - */
139 -static inline void json_jsonc_set_string(JSON_ENTRY *e,char *key,const char *value) {
140 - size_t length = strlen(key);
141 - e->type = JSON_STRING;
142 - memcpy(e->name,key,length);
143 - e->name[length] = 0x00;
144 - e->data.string = (char *) value;
145 -}
146 -
147 -
148 -#ifdef ENABLE_JSONC
149 -/**
150 - * JSONC set Boolean
151 - *
152 - * Set the boolean value of the structure JSON_ENTRY
153 - *
154 - * @param e the output structure
155 - * @param value the input value
156 - */
157 -static inline void json_jsonc_set_boolean(JSON_ENTRY *e,int value) {
158 - e->type = JSON_BOOLEAN;
159 - e->data.boolean = value;
160 -}
161 -
162 -/**
163 - * Parse Array
164 - *
165 - * Parse the array object.
166 - *
167 - * @param ptr the pointer for the object that we will parse.
168 - * @param callback_data additional data to be used together the callback function
169 - * @param callback_function function used to create a silencer.
170 - */
171 -static inline void json_jsonc_parse_array(json_object *ptr, void *callback_data,int (*callback_function)(struct json_entry *)) {
172 - int end = json_object_array_length(ptr);
173 - JSON_ENTRY e;
174 -
175 - if(end) {
176 - int i;
177 - i = 0;
178 -
179 - enum json_type type;
180 - do {
181 - json_object *jvalue = json_object_array_get_idx(ptr, i);
182 - if(jvalue) {
183 - e.callback_data = callback_data;
184 - e.type = JSON_OBJECT;
185 - callback_function(&e);
186 - json_object_object_foreach(jvalue, key, val) {
187 - type = json_object_get_type(val);
188 - if (type == json_type_array) {
189 - e.type = JSON_ARRAY;
190 - json_jsonc_parse_array(val, callback_data, callback_function);
191 - } else if (type == json_type_object) {
192 - json_walk(val,callback_data,callback_function);
193 - } else if (type == json_type_string) {
194 - json_jsonc_set_string(&e,key,json_object_get_string(val));
195 - callback_function(&e);
196 - } else if (type == json_type_boolean) {
197 - json_jsonc_set_boolean(&e,json_object_get_boolean(val));
198 - callback_function(&e);
199 - }
200 - }
201 - }
202 -
203 - } while (++i < end);
204 - }
205 -}
206 -#else
207 -
208 -/**
209 - * Walk string
210 - *
211 - * Set JSON_ENTRY to string and map the values from jsmntok_t.
212 - *
213 - * @param js the original string
214 - * @param t the tokens
215 - * @param start the first position
216 - * @param e the output structure.
217 - *
218 - * @return It always return 1
219 - */
220 -size_t json_walk_string(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e)
221 -{
222 - char old = js[t[start].end];
223 - js[t[start].end] = '\0';
224 - e->original_string = &js[t[start].start];
225 -
226 - e->type = JSON_STRING;
227 - e->data.string = e->original_string;
228 - if(e->callback_function) e->callback_function(e);
229 - js[t[start].end] = old;
230 - return 1;
231 -}
232 -
233 -/**
234 - * Walk Primitive
235 - *
236 - * Define the data type of the string
237 - *
238 - * @param js the original string
239 - * @param t the tokens
240 - * @param start the first position
241 - * @param e the output structure.
242 - *
243 - * @return It always return 1
244 - */
245 -size_t json_walk_primitive(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e)
246 -{
247 - char old = js[t[start].end];
248 - js[t[start].end] = '\0';
249 - e->original_string = &js[t[start].start];
250 -
251 - switch(e->original_string[0]) {
252 - case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
253 - case '8': case '9': case '-': case '.':
254 - e->type = JSON_NUMBER;
255 - e->data.number = strtold(e->original_string, NULL);
256 - break;
257 -
258 - case 't': case 'T':
259 - e->type = JSON_BOOLEAN;
260 - e->data.boolean = 1;
261 - break;
262 -
263 - case 'f': case 'F':
264 - e->type = JSON_BOOLEAN;
265 - e->data.boolean = 0;
266 - break;
267 -
268 - case 'n': case 'N':
269 - default:
270 - e->type = JSON_NULL;
271 - break;
272 - }
273 - if(e->callback_function) e->callback_function(e);
274 - js[t[start].end] = old;
275 - return 1;
276 -}
277 -
278 -/**
279 - * Array
280 - *
281 - * Measure the array length
282 - *
283 - * @param js the original string
284 - * @param t the tokens
285 - * @param nest the length of structure t
286 - * @param start the first position
287 - * @param e the output structure.
288 - *
289 - * @return It returns the array length
290 - */
291 -size_t json_walk_array(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e)
292 -{
293 - JSON_ENTRY ne = {
294 - .name = "",
295 - .fullname = "",
296 - .callback_data = NULL,
297 - .callback_function = NULL
298 - };
299 -
300 - char old = js[t[start].end];
301 - js[t[start].end] = '\0';
302 - ne.original_string = &js[t[start].start];
303 -
304 - memcpy(&ne, e, sizeof(JSON_ENTRY));
305 - ne.type = JSON_ARRAY;
306 - ne.data.items = t[start].size;
307 - ne.callback_function = NULL;
308 - ne.name[0]='\0';
309 - ne.fullname[0]='\0';
310 - if(e->callback_function) e->callback_function(&ne);
311 - js[t[start].end] = old;
312 -
313 - size_t i, init = start, size = t[start].size;
314 -
315 - start++;
316 - for(i = 0; i < size ; i++) {
317 - ne.pos = i;
318 - if (!e->name || !e->fullname || strlen(e->name) > JSON_NAME_LEN - 24 || strlen(e->fullname) > JSON_FULLNAME_LEN -24) {
319 - info("JSON: JSON walk_array ignoring element with name:%s fullname:%s",e->name, e->fullname);
320 - continue;
321 - }
322 - sprintf(ne.name, "%s[%lu]", e->name, i);
323 - sprintf(ne.fullname, "%s[%lu]", e->fullname, i);
324 -
325 - switch(t[start].type) {
326 - case JSMN_PRIMITIVE:
327 - start += json_walk_primitive(js, t, start, &ne);
328 - break;
329 -
330 - case JSMN_OBJECT:
331 - start += json_walk_object(js, t, nest + 1, start, &ne);
332 - break;
333 -
334 - case JSMN_ARRAY:
335 - start += json_walk_array(js, t, nest + 1, start, &ne);
336 - break;
337 -
338 - case JSMN_STRING:
339 - start += json_walk_string(js, t, start, &ne);
340 - break;
341 - }
342 - }
343 - return start - init;
344 -}
345 -
346 -/**
347 - * Object
348 - *
349 - * Measure the Object length
350 - *
351 - * @param js the original string
352 - * @param t the tokens
353 - * @param nest the length of structure t
354 - * @param start the first position
355 - * @param e the output structure.
356 - *
357 - * @return It returns the Object length
358 - */
359 -size_t json_walk_object(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e)
360 -{
361 - JSON_ENTRY ne = {
362 - .name = "",
363 - .fullname = "",
364 - .callback_data = NULL,
365 - .callback_function = NULL
366 - };
367 -
368 - char old = js[t[start].end];
369 - js[t[start].end] = '\0';
370 - ne.original_string = &js[t[start].start];
371 - memcpy(&ne, e, sizeof(JSON_ENTRY));
372 - ne.type = JSON_OBJECT;
373 - ne.callback_function = NULL;
374 - if(e->callback_function) e->callback_function(&ne);
375 - js[t[start].end] = old;
376 -
377 - int key = 1;
378 - size_t i, init = start, size = t[start].size;
379 -
380 - start++;
381 - for(i = 0; i < size ; i++) {
382 - switch(t[start].type) {
383 - case JSMN_PRIMITIVE:
384 - start += json_walk_primitive(js, t, start, &ne);
385 - key = 1;
386 - break;
387 -
388 - case JSMN_OBJECT:
389 - start += json_walk_object(js, t, nest + 1, start, &ne);
390 - key = 1;
391 - break;
392 -
393 - case JSMN_ARRAY:
394 - start += json_walk_array(js, t, nest + 1, start, &ne);
395 - key = 1;
396 - break;
397 -
398 - case JSMN_STRING:
399 - default:
400 - if(key) {
401 - int len = t[start].end - t[start].start;
402 - if (unlikely(len>JSON_NAME_LEN)) len=JSON_NAME_LEN;
403 - strncpy(ne.name, &js[t[start].start], len);
404 - ne.name[len] = '\0';
405 - len=strlen(e->fullname) + strlen(e->fullname[0]?".":"") + strlen(ne.name);
406 - char *c = mallocz((len+1)*sizeof(char));
407 - sprintf(c,"%s%s%s", e->fullname, e->fullname[0]?".":"", ne.name);
408 - if (unlikely(len>JSON_FULLNAME_LEN)) len=JSON_FULLNAME_LEN;
409 - strncpy(ne.fullname, c, len);
410 - freez(c);
411 - start++;
412 - key = 0;
413 - }
414 - else {
415 - start += json_walk_string(js, t, start, &ne);
416 - key = 1;
417 - }
418 - break;
419 - }
420 - }
421 - return start - init;
422 -}
423 -#endif
424 -
425 -/**
426 - * Tree
427 - *
428 - * Call the correct walk function according its type.
429 - *
430 - * @param t the json object to work
431 - * @param callback_data additional data to be used together the callback function
432 - * @param callback_function function used to create a silencer.
433 - *
434 - * @return It always return 1
435 - */
436 -#ifdef ENABLE_JSONC
437 -size_t json_walk(json_object *t, void *callback_data, int (*callback_function)(struct json_entry *)) {
438 - JSON_ENTRY e;
439 -
440 - e.callback_data = callback_data;
441 - enum json_type type;
442 - json_object_object_foreach(t, key, val) {
443 - type = json_object_get_type(val);
444 - if (type == json_type_array) {
445 - e.type = JSON_ARRAY;
446 - json_jsonc_parse_array(val,NULL,health_silencers_json_read_callback);
447 - } else if (type == json_type_object) {
448 - e.type = JSON_OBJECT;
449 - } else if (type == json_type_string) {
450 - json_jsonc_set_string(&e,key,json_object_get_string(val));
451 - callback_function(&e);
452 - } else if (type == json_type_boolean) {
453 - json_jsonc_set_boolean(&e,json_object_get_boolean(val));
454 - callback_function(&e);
455 - }
456 - }
457 -
458 - return 1;
459 -}
460 -#else
461 -/**
462 - * Tree
463 - *
464 - * Call the correct walk function according its type.
465 - *
466 - * @param js the original string
467 - * @param t the tokens
468 - * @param callback_data additional data to be used together the callback function
469 - * @param callback_function function used to create a silencer.
470 - *
471 - * @return It always return 1
472 - */
473 -size_t json_walk_tree(char *js, jsmntok_t *t, void *callback_data, int (*callback_function)(struct json_entry *))
474 -{
475 - JSON_ENTRY e = {
476 - .name = "",
477 - .fullname = "",
478 - .callback_data = callback_data,
479 - .callback_function = callback_function
480 - };
481 -
482 - switch (t[0].type) {
483 - case JSMN_OBJECT:
484 - e.type = JSON_OBJECT;
485 - json_walk_object(js, t, 0, 0, &e);
486 - break;
487 -
488 - case JSMN_ARRAY:
489 - e.type = JSON_ARRAY;
490 - json_walk_array(js, t, 0, 0, &e);
491 - break;
492 -
493 - case JSMN_PRIMITIVE:
494 - case JSMN_STRING:
495 - break;
496 - }
497 -
498 - return 1;
499 -}
500 -#endif
501 -
502 -/**
503 - * JSON Parse
504 - *
505 - * Parse the json message with the callback function
506 - *
507 - * @param js the string that the callback function will parse
508 - * @param callback_data additional data to be used together the callback function
509 - * @param callback_function function used to create a silencer.
510 - *
511 - * @return JSON_OK case everything happend as expected, JSON_CANNOT_PARSE case there were errors in the
512 - * parsing procces and JSON_CANNOT_DOWNLOAD case the string given(js) is NULL.
513 - */
514 -int json_parse(char *js, void *callback_data, int (*callback_function)(JSON_ENTRY *))
515 -{
516 - if(js) {
517 -#ifdef ENABLE_JSONC
518 - json_object *tokens = json_tokenise(js);
519 -#else
520 - size_t count;
521 - jsmntok_t *tokens = json_tokenise(js, strlen(js), &count);
522 -#endif
523 -
524 - if(tokens) {
525 -#ifdef ENABLE_JSONC
526 - json_walk(tokens, callback_data, callback_function);
527 - json_object_put(tokens);
528 -#else
529 - json_walk_tree(js, tokens, callback_data, callback_function);
530 - freez(tokens);
531 -#endif
532 - return JSON_OK;
533 - }
534 -
535 - return JSON_CANNOT_PARSE;
536 - }
537 -
538 - return JSON_CANNOT_DOWNLOAD;
539 -}
540 -
541 -/*
542 -int json_test(char *str)
543 -{
544 - return json_parse(str, NULL, json_callback_print);
545 -}
546 - */
\ No newline at end of file
libnetdata/json/json.h deleted
-72
@@ -1,72 +0,0 @@
1 -#ifndef CHECKIN_JSON_H
2 -#define CHECKIN_JSON_H 1
3 -
4 -
5 -#if ENABLE_JSONC
6 -# include <json-c/json.h>
7 -#endif
8 -
9 -#include "jsmn.h"
10 -
11 -//https://www.ibm.com/support/knowledgecenter/en/SS9H2Y_7.6.0/com.ibm.dp.doc/json_parserlimits.html
12 -#define JSON_NAME_LEN 256
13 -#define JSON_FULLNAME_LEN 1024
14 -
15 -typedef enum {
16 - JSON_OBJECT = 0,
17 - JSON_ARRAY = 1,
18 - JSON_STRING = 2,
19 - JSON_NUMBER = 3,
20 - JSON_BOOLEAN = 4,
21 - JSON_NULL = 5,
22 -} JSON_ENTRY_TYPE;
23 -
24 -typedef struct json_entry {
25 - JSON_ENTRY_TYPE type;
26 - char name[JSON_NAME_LEN + 1];
27 - char fullname[JSON_FULLNAME_LEN + 1];
28 - union {
29 - char *string; // type == JSON_STRING
30 - long double number; // type == JSON_NUMBER
31 - int boolean; // type == JSON_BOOLEAN
32 - size_t items; // type == JSON_ARRAY
33 - } data;
34 - size_t pos; // the position of this item in its parent
35 -
36 - char *original_string;
37 -
38 - void *callback_data;
39 - int (*callback_function)(struct json_entry *);
40 -} JSON_ENTRY;
41 -
42 -// ----------------------------------------------------------------------------
43 -// public functions
44 -
45 -#define JSON_OK 0
46 -#define JSON_CANNOT_DOWNLOAD 1
47 -#define JSON_CANNOT_PARSE 2
48 -
49 -int json_parse(char *js, void *callback_data, int (*callback_function)(JSON_ENTRY *));
50 -
51 -
52 -// ----------------------------------------------------------------------------
53 -// private functions
54 -
55 -#ifdef ENABLE_JSONC
56 -json_object *json_tokenise(char *js);
57 -size_t json_walk(json_object *t, void *callback_data, int (*callback_function)(struct json_entry *));
58 -#else
59 -jsmntok_t *json_tokenise(char *js, size_t len, size_t *count);
60 -size_t json_walk_tree(char *js, jsmntok_t *t, void *callback_data, int (*callback_function)(struct json_entry *));
61 -#endif
62 -
63 -size_t json_walk_object(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e);
64 -size_t json_walk_array(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e);
65 -size_t json_walk_string(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e);
66 -size_t json_walk_primitive(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e);
67 -
68 -int json_callback_print(JSON_ENTRY *e);
69 -
70 -
71 -
72 -#endif
\ No newline at end of file
libnetdata/libnetdata.h
-2
@@ -310,7 +310,5 @@ extern char *netdata_configured_host_prefix;
310 #include "statistical/statistical.h"
311 #include "adaptive_resortable_list/adaptive_resortable_list.h"
312 #include "url/url.h"
313 -#include "json/json.h"
314 -#include "health/health.h"
313
314 #endif // NETDATA_LIB_H
netdata-installer.sh
-2
@@ -175,7 +175,6 @@ USAGE: ${PROGRAM} [options]
175 --libs-are-really-here If you get errors about missing zlib or libuuid but you know it is available, you might
176 have a broken pkg-config. Use this option to proceed without checking pkg-config.
177 --disable-telemetry Use this flag to opt-out from our anonymous telemetry progam.
178 - --enable-json Enable to use JSON-C library instead the internal Netdata library.
178
179 Netdata will by default be compiled with gcc optimization -O2
180 If you need to pass different CFLAGS, use something like this:
@@ -223,7 +222,6 @@ while [ -n "${1}" ]; do
222 "--disable-x86-sse") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-x86-sse/} --disable-x86-sse";;
223 "--disable-telemetry") NETDATA_DISABLE_TELEMETRY=1;;
224 "--disable-go") NETDATA_DISABLE_GO=1;;
226 - "--enable-jsonc") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-jsonc/} --enable-jsonc";;
225 "--install")
226 NETDATA_PREFIX="${2}/netdata"
227 shift 1
tests/health_mgmtapi/expected_list/ALARM_CPU_IOWAIT-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_iowait" }, { "alarm": "*10min_cpu_usage *load_trigger" } ] }
tests/health_mgmtapi/expected_list/ALARM_CPU_USAGE-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger", "context": "system.cpu" }, { "alarm": "*10min_cpu_usage *load_trigger", "chart": "system.load" } ] }
tests/health_mgmtapi/expected_list/CONTEXT_SYSTEM_CPU-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "DISABLE", "silencers": [ { "context": "system.cpu" }, { "chart": "system.load" } ] }
tests/health_mgmtapi/expected_list/DISABLE-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "DISABLE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] }
tests/health_mgmtapi/expected_list/DISABLE_ALL-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": true, "type": "DISABLE", "silencers": [] }
tests/health_mgmtapi/expected_list/DISABLE_ALL_ERROR-list.json deleted
-1
@@ -1 +0,0 @@
1 -Auth Error
tests/health_mgmtapi/expected_list/DISABLE_SYSTEM_LOAD-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "DISABLE", "silencers": [ { "chart": "system.load" } ] }
tests/health_mgmtapi/expected_list/FAMILIES_LOAD-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "None", "silencers": [ { "families": "load" } ] }
tests/health_mgmtapi/expected_list/HOSTS-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [ { "hosts": "*" } ] }
tests/health_mgmtapi/expected_list/RESET-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "None", "silencers": [] }
tests/health_mgmtapi/expected_list/SILENCE-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] }
tests/health_mgmtapi/expected_list/SILENCE_2-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [ { "families": "load" } ] }
tests/health_mgmtapi/expected_list/SILENCE_3-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [] } WARNING: SILENCE or DISABLE command is ineffective without defining any alarm selectors.
tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger", "chart": "system.load" } ] }
tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE_LOAD_TRIGGER-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] }
tests/health_mgmtapi/expected_list/SILENCE_ALL-list.json deleted
-1
@@ -1 +0,0 @@
1 -{ "all": true, "type": "SILENCE", "silencers": [] }
tests/health_mgmtapi/health-cmdapi-test.sh.in
+2 -38
@@ -27,7 +27,7 @@ check () {
27 elif [ "${r}" != "${2}" ] ; then
28 echo -e " ${GRAY}WARNING: 'Got ${r}'. Expected '${2}'"
29 iter=$((iter+1))
30 - if [ $iter -lt 10 ] ; then
30 + if [ $iter -lt 10 ] ; then
31 echo -e " ${GRAY}Repeating test "
32 check "$1" "$2"
33 else
@@ -53,20 +53,6 @@ cmd () {
53 fi
54 }
55
56 -check_list() {
57 - RESPONSE=$(curl -s "http://$URL/api/v1/manage/health?cmd=LIST" -H "X-Auth-Token: $TOKEN" 2>&1)
58 -
59 - NAME="$1-list.json"
60 - echo $RESPONSE > $NAME
61 - diff $NAME expected_list/$NAME 1>/dev/null 2>&1
62 - if [ $? -eq 0 ]; then
63 - echo -e "${GREEN}Success: The list command got the correct answer for $NAME!"
64 - else
65 - echo -e "${RED}ERROR: the files $NAME and expected_list/$NAME does not match."
66 - exit 1
67 - fi
68 -}
69 -
56 WHITE='\033[0;37m'
57 RED='\033[0;31m'
58 GREEN='\033[0;32m'
@@ -104,13 +90,11 @@ err=0
90 # Test default state
91 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
92 check "Default State" "False False False False False False"
107 - check_list "RESET"
93
94 # Test auth failure
95 TOKEN="Wrong token"
96 cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_AUTHERROR"
97 check "Default State" "False False False False False False"
113 - check_list "DISABLE_ALL_ERROR"
98
99 # Set correct token
100 TOKEN="${CORRECT_TOKEN}"
@@ -118,107 +102,87 @@ err=0
102 # Test disable
103 cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_DISABLEALL"
104 check "All disabled" "True False True False True False"
121 - check_list "DISABLE_ALL"
105
106 # Reset
107 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
108 check "Default State" "False False False False False False"
126 - check_list "RESET"
109
110 # Test silence
111 cmd "cmd=SILENCE ALL" "$HEALTH_CMDAPI_MSG_SILENCEALL"
112 check "All silenced" "False True False True False True"
131 - check_list "SILENCE_ALL"
113
114 # Reset
115 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
116 check "Default State" "False False False False False False"
136 - check_list "RESET"
117
118 # Add silencer by name
119 printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_ADDED"
120 cmd "cmd=SILENCE&alarm=*10min_cpu_usage *load_trigger" "${resp}"
121 check "Silence notifications for alarm1 and load_trigger" "False True False False False True"
142 - check_list "SILENCE_ALARM_CPU_USAGE_LOAD_TRIGGER"
122
123 # Convert to disable health checks
124 cmd "cmd=DISABLE" "$HEALTH_CMDAPI_MSG_DISABLE"
125 check "Disable notifications for alarm1 and load_trigger" "True False False False True False"
147 - check_list "DISABLE"
126
127 # Convert back to silence notifications
128 cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE"
129 check "Silence notifications for alarm1 and load_trigger" "False True False False False True"
152 - check_list "SILENCE"
130
131 # Add second silencer by name
132 cmd "alarm=*10min_cpu_iowait" "$HEALTH_CMDAPI_MSG_ADDED"
133 check "Silence notifications for alarm1,alarm2 and load_trigger" "False True False True False True"
157 - check_list "ALARM_CPU_IOWAIT"
134
135 # Reset
136 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
161 - check_list "RESET"
137
138 # Add silencer by chart
139 printf -v resp "$HEALTH_CMDAPI_MSG_DISABLE\n$HEALTH_CMDAPI_MSG_ADDED"
140 cmd "cmd=DISABLE&chart=system.load" "${resp}"
141 check "Default State" "False False False False True False"
167 - check_list "DISABLE_SYSTEM_LOAD"
142
143 # Add silencer by context
144 cmd "context=system.cpu" "$HEALTH_CMDAPI_MSG_ADDED"
145 check "Default State" "True False True False True False"
172 - check_list "CONTEXT_SYSTEM_CPU"
146
147 # Reset
148 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
176 - check_list "RESET"
149
150 # Add second condition to a selector (AND)
151 printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_ADDED"
152 cmd "cmd=SILENCE&alarm=*10min_cpu_usage *load_trigger&chart=system.load" "${resp}"
153 check "Silence notifications load_trigger" "False False False False False True"
182 - check_list "SILENCE_ALARM_CPU_USAGE"
154
155 # Add second selector with two conditions
156 cmd "alarm=*10min_cpu_usage *load_trigger&context=system.cpu" "$HEALTH_CMDAPI_MSG_ADDED"
157 check "Silence notifications load_trigger" "False True False False False True"
187 - check_list "ALARM_CPU_USAGE"
158
159 # Reset
160 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
191 - check_list "RESET"
161
162 # Add silencer without a command to disable or silence alarms
163 printf -v resp "$HEALTH_CMDAPI_MSG_ADDED\n$HEALTH_CMDAPI_MSG_STYPEWARNING"
164 cmd "families=load" "${resp}"
165 check "Family selector with no command" "False False False False False False"
197 - check_list "FAMILIES_LOAD"
166
167 # Add silence command
168 cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE"
169 check "Silence family load" "False False False False False True"
202 - check_list "SILENCE_2"
170
171 # Reset
172 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
206 - check_list "RESET"
173
174 # Add command without silencers
175 printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_NOSELECTORWARNING"
176 cmd "cmd=SILENCE" "${resp}"
177 check "Command with no selector" "False False False False False False"
212 - check_list "SILENCE_3"
178
179 # Add hosts silencer
180 cmd "hosts=*" "$HEALTH_CMDAPI_MSG_ADDED"
181 check "Silence all hosts" "False True False True False True"
217 - check_list "HOSTS"
182
183 # Reset
184 cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
221 - check_list "RESET"
185 +
186
187 if [ $err -gt 0 ] ; then
188 echo "$err error(s) found"
web/api/health/README.md
+1 -50
@@ -45,7 +45,6 @@ The following will return an SVG badge of the alarm named `NAME`, attached to th
45 ## Health Management API
46
47 Netdata v1.12 and beyond provides a command API to control health checks and notifications at runtime. The feature is especially useful for maintenance periods, during which you receive meaningless alarms.
48 -From Netdata v1.16.0 and beyond, the configuration controlled via the API commands is [persisted across netdata restarts](#persistence).
48
49 Specifically, the API allows you to:
50 - Disable health checks completely. Alarm conditions will not be evaluated at all and no entries will be added to the alarm log.
@@ -143,43 +142,6 @@ Example 2.2: Add one more selector, to also silence alarms for cpu1 and cpu2
142 http://localhost/api/v1/manage/health?families=cpu1 cpu2
143 ```
144
146 -### List silencers
147 -
148 -The command `LIST` was added in netdata v1.16.0 and returns a JSON with the current status of the silencers.
149 -
150 -```
151 - curl "http://myserver/api/v1/manage/health?cmd=LIST" -H "X-Auth-Token: Mytoken"
152 -```
153 -
154 -As an example, the following response shows that we have two silencers configured, one for an alarm called `samplealarm` and one for alarms with context `random` on host `myhost`
155 -```
156 -json
157 -{
158 - "all": false,
159 - "type": "SILENCE",
160 - "silencers": [
161 - {
162 - "alarm": "samplealarm"
163 - },
164 - {
165 - "context": "random",
166 - "hosts": "myhost"
167 - }
168 - ]
169 -}
170 -```
171 -
172 -The response below shows that we have disabled all health checks.
173 -
174 -```
175 -json
176 -{
177 - "all": true,
178 - "type": "DISABLE",
179 - "silencers": []
180 -}
181 -```
182 -
145 ### Responses
146
147 - "Auth Error" : Token authentication failed
@@ -189,21 +151,10 @@ json
151 - "Health checks disabled for alarms matching the selectors" : Added to the response for a cmd=DISABLE
152 - "Alarm notifications silenced for alarms matching the selectors" : Added to the response for a cmd=SILENCE
153 - "Alarm selector added" : Added to the response when a new selector is added
154 +- "Invalid key. Ignoring it." : Wrong name of a parameter. Added to the response and ignored.
155 - "WARNING: Added alarm selector to silence/disable alarms without a SILENCE or DISABLE command." : Added to the response if a selector is added without a selector-specific command.
156 - "WARNING: SILENCE or DISABLE command is ineffective without defining any alarm selectors." : Added to the response if a selector-specific command is issued without a selector.
157
195 -### Persistence
196 -
197 -From netdata v1.13.1 and beyond, the silencers configuration is persisted to disk and loaded when netdata starts.
198 -The JSON string returned by the [LIST command](#list-silencers) is automatically saved to the `silencers file`, every time a command alters the silencers configuration.
199 -The file's location is configurable in `netdata.conf`. The default is shown below:
200 -
201 -```
202 -[health]
203 - # silencers file = /var/lib/netdata/health.silencers.json
204 -```
205 -
206 -
158 ### Further reading
159
160 The test script under [tests/health_mgmtapi](../../../tests/health_mgmtapi) contains a series of tests that you can either run or read through to understand the various calls and responses better.
web/api/health/health_cmdapi.c
+67 -107
@@ -1,16 +1,17 @@
1 //
2 -// Created by Christopher on 11/12/18.
2 +// Created by christopher on 11/12/18.
3 //
4
5 #include "health_cmdapi.h"
6
7 -/**
8 - * Free Silencers
9 - *
10 - * Clean the silencer structure
11 - *
12 - * @param t is the structure that will be cleaned.
13 - */
7 +
8 +static SILENCER *create_silencer(void) {
9 + SILENCER *t = callocz(1, sizeof(SILENCER));
10 + debug(D_HEALTH, "HEALTH command API: Created empty silencer");
11 +
12 + return t;
13 +}
14 +
15 void free_silencers(SILENCER *t) {
16 if (!t) return;
17 if (t->next) free_silencers(t->next);
@@ -30,104 +31,38 @@ void free_silencers(SILENCER *t) {
31 return;
32 }
33
33 -/**
34 - * Silencers to JSON Entry
35 - *
36 - * Fill the buffer with the other values given.
37 - *
38 - * @param wb a pointer to the output buffer
39 - * @param var the json variable
40 - * @param val the json value
41 - * @param hasprev has it a previous value?
42 - *
43 - * @return
44 - */
45 -int health_silencers2json_entry(BUFFER *wb, char* var, char* val, int hasprev) {
46 - if (val) {
47 - buffer_sprintf(wb, "%s\n\t\t\t\"%s\": \"%s\"", (hasprev)?",":"", var, val);
48 - return 1;
49 - } else {
50 - return hasprev;
51 - }
52 -}
34
54 -/**
55 - * Silencer to JSON
56 - *
57 - * Write the silencer values using JSON format inside a buffer.
58 - *
59 - * @param wb is the buffer to write the silencers.
60 - */
61 -void health_silencers2json(BUFFER *wb) {
62 - buffer_sprintf(wb, "{\n\t\"all\": %s,"
63 - "\n\t\"type\": \"%s\","
64 - "\n\t\"silencers\": [",
65 - (silencers->all_alarms)?"true":"false",
66 - (silencers->stype == STYPE_NONE)?"None":((silencers->stype == STYPE_DISABLE_ALARMS)?"DISABLE":"SILENCE"));
67 -
68 - SILENCER *silencer;
69 - int i = 0, j = 0;
70 - for(silencer = silencers->silencers; silencer ; silencer = silencer->next) {
71 - if(likely(i)) buffer_strcat(wb, ",");
72 - buffer_strcat(wb, "\n\t\t{");
73 - j=health_silencers2json_entry(wb, HEALTH_ALARM_KEY, silencer->alarms, j);
74 - j=health_silencers2json_entry(wb, HEALTH_CHART_KEY, silencer->charts, j);
75 - j=health_silencers2json_entry(wb, HEALTH_CONTEXT_KEY, silencer->contexts, j);
76 - j=health_silencers2json_entry(wb, HEALTH_HOST_KEY, silencer->hosts, j);
77 - health_silencers2json_entry(wb, HEALTH_FAMILIES_KEY, silencer->families, j);
78 - j=0;
79 - buffer_strcat(wb, "\n\t\t}");
80 - i++;
81 - }
82 - if(likely(i)) buffer_strcat(wb, "\n\t");
83 - buffer_strcat(wb, "]\n}\n");
84 -}
35
86 -/**
87 - * Silencer to FILE
88 - *
89 - * Write the sliencer buffer to a file.
90 - * @param wb
91 - */
92 -void health_silencers2file(BUFFER *wb) {
93 - if (wb->len == 0) return;
94 -
95 - FILE *fd = fopen(silencers_filename, "wb");
96 - if(fd) {
97 - size_t written = (size_t)fprintf(fd, "%s", wb->buffer) ;
98 - if (written == wb->len ) {
99 - info("Silencer changes written to %s", silencers_filename);
100 - }
101 - fclose(fd);
102 - return;
103 - }
104 - error("Silencer changes could not be written to %s. Error %s", silencers_filename, strerror(errno));
105 -}
106 -
107 -/**
108 - * Request V1 MGMT Health
109 - *
110 - * Function called by api to management the health.
111 - *
112 - * @param host main structure with client information!
113 - * @param w is the structure with all information of the client request.
114 - * @param url is the url that netdata is working
115 - *
116 - * @return It returns 200 on success and another code otherwise.
117 - */
36 int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, char *url) {
37 int ret = 400;
38 (void) host;
39
40 +
41 +
42 BUFFER *wb = w->response.data;
43 buffer_flush(wb);
44 wb->contenttype = CT_TEXT_PLAIN;
45
46 buffer_flush(w->response.data);
47
128 - //Local instance of the silencer
48 + static uint32_t
49 + hash_alarm = 0,
50 + hash_template = 0,
51 + hash_chart = 0,
52 + hash_context = 0,
53 + hash_host = 0,
54 + hash_families = 0;
55 +
56 + if (unlikely(!hash_alarm)) {
57 + hash_alarm = simple_uhash(HEALTH_ALARM_KEY);
58 + hash_template = simple_uhash(HEALTH_TEMPLATE_KEY);
59 + hash_chart = simple_uhash(HEALTH_CHART_KEY);
60 + hash_context = simple_uhash(HEALTH_CONTEXT_KEY);
61 + hash_host = simple_uhash(HEALTH_HOST_KEY);
62 + hash_families = simple_uhash(HEALTH_FAMILIES_KEY);
63 + }
64 +
65 SILENCER *silencer = NULL;
130 - int config_changed = 1;
66
67 if (!w->auth_bearer_token) {
68 buffer_strcat(wb, HEALTH_CMDAPI_MSG_AUTHERROR);
@@ -150,7 +85,6 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
85
86 // name and value are now the parameters
87 if (!strcmp(key, "cmd")) {
153 - //In this "if" we are working with the global silencers.
88 if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) {
89 silencers->all_alarms = 1;
90 silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
@@ -171,19 +105,50 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
105 free_silencers(silencers->silencers);
106 silencers->silencers = NULL;
107 buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET);
174 - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_LIST)) {
175 - w->response.data->contenttype = CT_APPLICATION_JSON;
176 - health_silencers2json(wb);
177 - config_changed=0;
108 }
109 } else {
180 - //In this else we work with local silencer
181 - silencer = health_silencers_addparam(silencer,key,value);
110 + uint32_t hash = simple_uhash(key);
111 + if (unlikely(silencer == NULL)) {
112 + if (
113 + (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) ||
114 + (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) ||
115 + (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) ||
116 + (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) ||
117 + (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) ||
118 + (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY))
119 + ) {
120 + silencer = create_silencer();
121 + }
122 + }
123 +
124 + if (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
125 + silencer->alarms = strdupz(value);
126 + silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT);
127 + } else if (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) {
128 + silencer->charts = strdupz(value);
129 + silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT);
130 + } else if (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) {
131 + silencer->contexts = strdupz(value);
132 + silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT);
133 + } else if (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) {
134 + silencer->hosts = strdupz(value);
135 + silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT);
136 + } else if (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
137 + silencer->families = strdupz(value);
138 + silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT);
139 + } else {
140 + buffer_strcat(wb, HEALTH_CMDAPI_MSG_INVALID_KEY);
141 + }
142 }
183 - }
143
144 + }
145 if (likely(silencer)) {
186 - health_silencers_add(silencer);
146 + // Add the created instance to the linked list in silencers
147 + silencer->next = silencers->silencers;
148 + silencers->silencers = silencer;
149 + debug(D_HEALTH, "HEALTH command API: Added silencer %s:%s:%s:%s:%s", silencer->alarms,
150 + silencer->charts, silencer->contexts, silencer->hosts, silencer->families
151 + );
152 buffer_strcat(wb, HEALTH_CMDAPI_MSG_ADDED);
153 if (silencers->stype == STYPE_NONE) {
154 buffer_strcat(wb, HEALTH_CMDAPI_MSG_STYPEWARNING);
@@ -197,10 +162,5 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
162 }
163 w->response.data = wb;
164 buffer_no_cacheable(w->response.data);
200 - if (ret == 200 && config_changed) {
201 - BUFFER *jsonb = buffer_create(200);
202 - health_silencers2json(jsonb);
203 - health_silencers2file(jsonb);
204 - }
165 return ret;
166 }
web/api/health/health_cmdapi.h
+1 -1
@@ -12,7 +12,6 @@
12 #define HEALTH_CMDAPI_CMD_SILENCE "SILENCE"
13 #define HEALTH_CMDAPI_CMD_DISABLE "DISABLE"
14 #define HEALTH_CMDAPI_CMD_RESET "RESET"
15 -#define HEALTH_CMDAPI_CMD_LIST "LIST"
15
16 #define HEALTH_CMDAPI_MSG_AUTHERROR "Auth Error\n"
17 #define HEALTH_CMDAPI_MSG_SILENCEALL "All alarm notifications are silenced\n"
@@ -21,6 +20,7 @@
20 #define HEALTH_CMDAPI_MSG_DISABLE "Health checks disabled for alarms matching the selectors\n"
21 #define HEALTH_CMDAPI_MSG_SILENCE "Alarm notifications silenced for alarms matching the selectors\n"
22 #define HEALTH_CMDAPI_MSG_ADDED "Alarm selector added\n"
23 +#define HEALTH_CMDAPI_MSG_INVALID_KEY "Invalid key. Ignoring it.\n"
24 #define HEALTH_CMDAPI_MSG_STYPEWARNING "WARNING: Added alarm selector to silence/disable alarms without a SILENCE or DISABLE command.\n"
25 #define HEALTH_CMDAPI_MSG_NOSELECTORWARNING "WARNING: SILENCE or DISABLE command is ineffective without defining any alarm selectors.\n"
26
web/api/netdata-swagger.json
+2 -3
@@ -664,7 +664,7 @@
664 {
665 "name": "cmd",
666 "in": "query",
667 - "description": "DISABLE ALL: No alarm criteria are evaluated, nothing is written in the alarm log. SILENCE ALL: No notifications are sent. RESET: Return to the default state. DISABLE/SILENCE: Set the mode to be used for the alarms matching the criteria of the alarm selectors. LIST: Show active configuration.",
667 + "description": "DISABLE ALL: No alarm criteria are evaluated, nothing is written in the alarm log. SILENCE ALL: No notifications are sent. RESET: Return to the default state. DISABLE/SILENCE: Set the mode to be used for the alarms matching the criteria of the alarm selectors.",
668 "required": false,
669 "type": "string",
670 "enum": [
@@ -672,8 +672,7 @@
672 "SILENCE ALL",
673 "DISABLE",
674 "SILENCE",
675 - "RESET",
676 - "LIST"
675 + "RESET"
676 ]
677 },
678 {
web/api/netdata-swagger.yaml
+2 -2
@@ -437,10 +437,10 @@ paths:
437 parameters:
438 - name: cmd
439 in: query
440 - description: 'DISABLE ALL: No alarm criteria are evaluated, nothing is written in the alarm log. SILENCE ALL: No notifications are sent. RESET: Return to the default state. DISABLE/SILENCE: Set the mode to be used for the alarms matching the criteria of the alarm selectors. LIST: Show active configuration.'
440 + description: 'DISABLE ALL: No alarm criteria are evaluated, nothing is written in the alarm log. SILENCE ALL: No notifications are sent. RESET: Return to the default state. DISABLE/SILENCE: Set the mode to be used for the alarms matching the criteria of the alarm selectors.'
441 required: false
442 type: string
443 - enum: ['DISABLE ALL', 'SILENCE ALL', 'DISABLE', 'SILENCE', 'RESET', 'LIST']
443 + enum: ['DISABLE ALL', 'SILENCE ALL', 'DISABLE', 'SILENCE', 'RESET']
444 - name: alarm
445 in: query
446 description: 'The expression provided will match both `alarm` and `template` names.'