diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a90d680d9..e6109c2fc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,14 +130,6 @@ set(NETDATA_COMMON_CFLAGS ${NETDATA_COMMON_CFLAGS} ${OPENSSL_CFLAGS_OTHER}) set(NETDATA_COMMON_LIBRARIES ${NETDATA_COMMON_LIBRARIES} ${OPENSSL_LIBRARIES}) set(NETDATA_COMMON_INCLUDE_DIRS ${NETDATA_COMMON_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS}) -# ----------------------------------------------------------------------------- -# JSON-C used to health - -pkg_check_modules(JSON REQUIRED json-c) -set(NETDATA_COMMON_CFLAGS ${NETDATA_COMMON_CFLAGS} ${JSONC_CFLAGS_OTHER}) -set(NETDATA_COMMON_LIBRARIES ${NETDATA_COMMON_LIBRARIES} ${JSON_LIBRARIES}) -set(NETDATA_COMMON_INCLUDE_DIRS ${NETDATA_COMMON_INCLUDE_DIRS} ${JSON_INCLUDE_DIRS}) - # ----------------------------------------------------------------------------- # Detect libcap @@ -313,15 +305,8 @@ set(LIBNETDATA_FILES libnetdata/threads/threads.h libnetdata/url/url.c libnetdata/url/url.h - libnetdata/health/health.c - libnetdata/health/health.h libnetdata/socket/security.c - libnetdata/socket/security.h - libnetdata/json/json.c - libnetdata/json/json.h - libnetdata/json/jsmn.c - libnetdata/json/jsmn.h - ) + libnetdata/socket/security.h) add_library(libnetdata OBJECT ${LIBNETDATA_FILES}) diff --git a/Makefile.am b/Makefile.am index 2729af38ad..6dacd825ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -159,14 +159,8 @@ LIBNETDATA_FILES = \ libnetdata/storage_number/storage_number.h \ libnetdata/threads/threads.c \ libnetdata/threads/threads.h \ - libnetdata/url/url.c \ - libnetdata/url/url.h \ - libnetdata/json/jsmn.h \ - libnetdata/json/jsmn.c \ - libnetdata/json/json.h \ - libnetdata/json/json.c \ - libnetdata/health/health.c \ - libnetdata/health/health.h \ + libnetdata/url/url.c \ + libnetdata/url/url.h \ $(NULL) APPS_PLUGIN_FILES = \ @@ -512,12 +506,12 @@ endif NETDATA_COMMON_LIBS = \ $(OPTIONAL_MATH_LIBS) \ $(OPTIONAL_ZLIB_LIBS) \ + $(OPTIONAL_SSL_LIBS) \ $(OPTIONAL_UUID_LIBS) \ $(OPTIONAL_UV_LIBS) \ $(OPTIONAL_LZ4_LIBS) \ $(OPTIONAL_JUDY_LIBS) \ $(OPTIONAL_SSL_LIBS) \ - $(OPTIONAL_JSONC_LIBS) \ $(NULL) sbin_PROGRAMS += netdata diff --git a/configure.ac b/configure.ac index fcf1931fcc..1b021255a5 100644 --- a/configure.ac +++ b/configure.ac @@ -142,12 +142,6 @@ AC_ARG_ENABLE( , [enable_https="detect"] ) -AC_ARG_ENABLE( - [jsonc], - [AS_HELP_STRING([--enable-jsonc], [Enable JSON-C support @<:@default autodetect@:>@])], - , - [enable_jsonc="detect"] -) AC_ARG_ENABLE( [dbengine], [AS_HELP_STRING([--disable-dbengine], [disable netdata dbengine @<:@default autodetect@:>@])], @@ -353,20 +347,6 @@ AC_CHECK_LIB( OPTIONAL_SSL_CFLAGS="${SSL_CFLAGS}" OPTIONAL_SSL_LIBS="${SSL_LIBS}" -# ----------------------------------------------------------------------------- -# JSON-C library - -PKG_CHECK_MODULES([JSON],[json-c],AC_CHECK_LIB( - [json-c], - [json_object_get_type], - [JSONC_LIBS="-ljson-c"]),AC_CHECK_LIB( - [json], - [json_object_get_type], - [JSONC_LIBS="-ljson"]) - ) - -OPTIONAL_JSONC_LIBS="${JSONC_LIBS}" - # ----------------------------------------------------------------------------- # DB engine and HTTPS test "${enable_dbengine}" = "yes" -a -z "${UV_LIBS}" && \ @@ -401,22 +381,6 @@ fi AC_MSG_RESULT([${enable_https}]) AM_CONDITIONAL([ENABLE_HTTPS], [test "${enable_https}" = "yes"]) -# ----------------------------------------------------------------------------- -# JSON-C -test "${enable_jsonc}" = "yes" -a -z "${JSONC_LIBS}" && \ - AC_MSG_ERROR([JSON-C required but not found. Try installing 'libjson-c-dev' or 'json-c'.]) - -AC_MSG_CHECKING([if json-c should be used]) -if test "${enable_jsonc}" != "no" -a "${JSONC_LIBS}"; then - enable_jsonc="yes" - AC_DEFINE([ENABLE_JSONC], [1], [netdata json-c usability]) -else - enable_jsonc="no" -fi -AC_MSG_RESULT([${enable_jsonc}]) -AM_CONDITIONAL([ENABLE_JSONC], [test "${enable_jsonc}" = "yes"]) - - # ----------------------------------------------------------------------------- # compiler options @@ -1011,7 +975,6 @@ AC_SUBST([OPTIONAL_UV_LIBS]) AC_SUBST([OPTIONAL_LZ4_LIBS]) AC_SUBST([OPTIONAL_JUDY_LIBS]) AC_SUBST([OPTIONAL_SSL_LIBS]) -AC_SUBST([OPTIONAL_JSONC_LIBS]) AC_SUBST([OPTIONAL_NFACCT_CFLAGS]) AC_SUBST([OPTIONAL_NFACCT_LIBS]) AC_SUBST([OPTIONAL_ZLIB_CFLAGS]) @@ -1078,8 +1041,6 @@ AC_CONFIG_FILES([ libnetdata/config/Makefile libnetdata/dictionary/Makefile libnetdata/eval/Makefile - libnetdata/json/Makefile - libnetdata/health/Makefile libnetdata/locks/Makefile libnetdata/log/Makefile libnetdata/popen/Makefile diff --git a/health/health.c b/health/health.c index 55d44e955d..f92a1ba6b0 100644 --- a/health/health.c +++ b/health/health.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -#include <libnetdata/json/json.h> #include "health.h" struct health_cmdapi_thread_status { @@ -14,79 +13,18 @@ unsigned int default_health_enabled = 1; // ---------------------------------------------------------------------------- // health initialization -/** - * User Config directory - * - * Get the config directory for health and return it. - * - * @return a pointer to the user config directory - */ inline char *health_user_config_dir(void) { char buffer[FILENAME_MAX + 1]; snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_user_config_dir); return config_get(CONFIG_SECTION_HEALTH, "health configuration directory", buffer); } -/** - * Stock Config Directory - * - * Get the Stock config directory and return it. - * - * @return a pointer to the stock config directory. - */ inline char *health_stock_config_dir(void) { char buffer[FILENAME_MAX + 1]; snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_stock_config_dir); return config_get(CONFIG_SECTION_HEALTH, "stock health configuration directory", buffer); } - -/** - * Silencers init - * - * Function used to initialize the silencer structure. - */ -void health_silencers_init(void) { - silencers = mallocz(sizeof(SILENCERS)); - silencers->all_alarms=0; - silencers->stype=STYPE_NONE; - silencers->silencers=NULL; - - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/health.silencers.json", netdata_configured_varlib_dir); - silencers_filename = config_get(CONFIG_SECTION_HEALTH, "silencers file", filename); - - struct stat statbuf; - if (!stat(silencers_filename,&statbuf)) { - off_t length = statbuf.st_size; - if (length && length < HEALTH_SILENCERS_MAX_FILE_LEN) { - FILE *fd = fopen(silencers_filename, "r"); - if (fd) { - char *str = mallocz((length+1)* sizeof(char)); - if(str) { - fread(str, sizeof(char), length, fd); - str[length] = 0x00; - json_parse(str, NULL, health_silencers_json_read_callback); - freez(str); - info("Parsed health silencers file %s", silencers_filename); - } - fclose(fd); - } else { - error("Cannot open the file %s",silencers_filename); - } - } else { - 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); - } - } else { - error("Cannot open the file %s",silencers_filename); - } -} - -/** - * Health Init - * - * Initialize the health thread. - */ void health_init(void) { debug(D_HEALTH, "Health configuration initializing"); @@ -94,20 +32,11 @@ void health_init(void) { debug(D_HEALTH, "Health is disabled."); return; } - - health_silencers_init(); } // ---------------------------------------------------------------------------- // re-load health configuration -/** - * Reload host - * - * Reload configuration for a specific host. - * - * @param host the structure of the host that the function will reload the configuration. - */ void health_reload_host(RRDHOST *host) { if(unlikely(!host->health_enabled)) return; @@ -155,11 +84,6 @@ void health_reload_host(RRDHOST *host) { rrdhost_unlock(host); } -/** - * Reload - * - * Reload the host configuration for all hosts. - */ void health_reload(void) { rrd_rdlock(); @@ -501,16 +425,6 @@ SILENCE_TYPE check_silenced(RRDCALC *rc, char* host, SILENCERS *silencers) { return STYPE_NONE; } -/** - * Update Disabled Silenced - * - * Update the variable rrdcalc_flags of the structure RRDCALC according with the values of the host structure - * - * @param host structure that contains information about the host monitored. - * @param rc structure with information about the alarm - * - * @return It returns 1 case rrdcalc_flags is DISABLED or 0 otherwise - */ int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) { uint32_t rrdcalc_flags_old = rc->rrdcalc_flags; // Clear the flags @@ -540,15 +454,6 @@ int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) { return 0; } -/** - * Health Main - * - * The main thread of the health system. In this function all the alarms will be processed. - * - * @param ptr is a pointer to the netdata_static_thread structure. - * - * @return It always returns NULL - */ void *health_main(void *ptr) { netdata_thread_cleanup_push(health_main_cleanup, ptr); @@ -560,6 +465,11 @@ void *health_main(void *ptr) { unsigned int loop = 0; + silencers = mallocz(sizeof(SILENCERS)); + silencers->all_alarms=0; + silencers->stype=STYPE_NONE; + silencers->silencers=NULL; + while(!netdata_exit) { loop++; debug(D_HEALTH, "Health monitoring iteration no %u started", loop); @@ -613,7 +523,6 @@ void *health_main(void *ptr) { // the first loop is to lookup values from the db for (rc = host->alarms; rc; rc = rc->next) { - //case it is disabled I will get the next rc if (update_disabled_silenced(host, rc)) continue; diff --git a/health/health.h b/health/health.h index acbcf827c2..1511f36486 100644 --- a/health/health.h +++ b/health/health.h @@ -35,9 +35,16 @@ extern unsigned int default_health_enabled; #define HEALTH_LISTEN_BACKLOG 4096 #endif - +#define HEALTH_ALARM_KEY "alarm" +#define HEALTH_TEMPLATE_KEY "template" #define HEALTH_ON_KEY "on" - +#define HEALTH_CONTEXT_KEY "context" +#define HEALTH_CHART_KEY "chart" +#define HEALTH_HOST_KEY "hosts" +#define HEALTH_OS_KEY "os" +#define HEALTH_FAMILIES_KEY "families" +#define HEALTH_LOOKUP_KEY "lookup" +#define HEALTH_CALC_KEY "calc" #define HEALTH_EVERY_KEY "every" #define HEALTH_GREEN_KEY "green" #define HEALTH_RED_KEY "red" @@ -50,9 +57,38 @@ extern unsigned int default_health_enabled; #define HEALTH_DELAY_KEY "delay" #define HEALTH_OPTIONS_KEY "options" -#define HEALTH_SILENCERS_MAX_FILE_LEN 10000 +typedef struct silencer { + char *alarms; + SIMPLE_PATTERN *alarms_pattern; -char *silencers_filename; + char *hosts; + SIMPLE_PATTERN *hosts_pattern; + + char *contexts; + SIMPLE_PATTERN *contexts_pattern; + + char *charts; + SIMPLE_PATTERN *charts_pattern; + + char *families; + SIMPLE_PATTERN *families_pattern; + + struct silencer *next; +} SILENCER; + +typedef enum silence_type { + STYPE_NONE, + STYPE_DISABLE_ALARMS, + STYPE_SILENCE_NOTIFICATIONS +} SILENCE_TYPE; + +typedef struct silencers { + int all_alarms; + SILENCE_TYPE stype; + SILENCER *silencers; +} SILENCERS; + +SILENCERS *silencers; extern void health_init(void); extern void *health_main(void *ptr); diff --git a/health/health_config.c b/health/health_config.c index 54d11b6a1c..35fde90bc2 100644 --- a/health/health_config.c +++ b/health/health_config.c @@ -481,7 +481,7 @@ static int health_readfile(const char *filename, void *data) { if(append < HEALTH_CONF_MAX_LINE) continue; else { - error("Health configuration has too long multi-line at line %zu of file '%s'.", line, filename); + error("Health configuration has too long muli-line at line %zu of file '%s'.", line, filename); } } append = 0; diff --git a/libnetdata/Makefile.am b/libnetdata/Makefile.am index 8f41d82105..d2710f0a3e 100644 --- a/libnetdata/Makefile.am +++ b/libnetdata/Makefile.am @@ -21,8 +21,6 @@ SUBDIRS = \ storage_number \ threads \ url \ - json \ - health \ $(NULL) dist_noinst_DATA = \ diff --git a/libnetdata/health/Makefile.am b/libnetdata/health/Makefile.am deleted file mode 100644 index 9b7995f175..0000000000 --- a/libnetdata/health/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-or-later - -AUTOMAKE_OPTIONS = subdir-objects -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in - - -dist_noinst_DATA = \ - $(NULL) diff --git a/libnetdata/health/health.c b/libnetdata/health/health.c deleted file mode 100644 index b3d342d406..0000000000 --- a/libnetdata/health/health.c +++ /dev/null @@ -1,154 +0,0 @@ -#include "health.h" - -/** - * Create Silencer - * - * Allocate a new silencer to Netdata. - * - * @return It returns the address off the silencer on success and NULL otherwise - */ -SILENCER *create_silencer(void) { - SILENCER *t = callocz(1, sizeof(SILENCER)); - debug(D_HEALTH, "HEALTH command API: Created empty silencer"); - - return t; -} - -/** - * Health Silencers add - * - * Add more one silencer to the list of silenecers. - * - * @param silencer - */ -void health_silencers_add(SILENCER *silencer) { - // Add the created instance to the linked list in silencers - silencer->next = silencers->silencers; - silencers->silencers = silencer; - debug(D_HEALTH, "HEALTH command API: Added silencer %s:%s:%s:%s:%s", silencer->alarms, - silencer->charts, silencer->contexts, silencer->hosts, silencer->families - ); -} - -/** - * Silencers Add Parameter - * - * Create a new silencer and adjust the variables - * - * @param silencer a pointer to the silencer that will be adjusted - * @param key the key value sent by client - * @param value the value sent to the key - * - * @return It returns the silencer configured on success and NULL otherwise - */ -SILENCER *health_silencers_addparam(SILENCER *silencer, char *key, char *value) { - static uint32_t - hash_alarm = 0, - hash_template = 0, - hash_chart = 0, - hash_context = 0, - hash_host = 0, - hash_families = 0; - - if (unlikely(!hash_alarm)) { - hash_alarm = simple_uhash(HEALTH_ALARM_KEY); - hash_template = simple_uhash(HEALTH_TEMPLATE_KEY); - hash_chart = simple_uhash(HEALTH_CHART_KEY); - hash_context = simple_uhash(HEALTH_CONTEXT_KEY); - hash_host = simple_uhash(HEALTH_HOST_KEY); - hash_families = simple_uhash(HEALTH_FAMILIES_KEY); - } - - uint32_t hash = simple_uhash(key); - if (unlikely(silencer == NULL)) { - if ( - (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) || - (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) || - (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) || - (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) || - (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) || - (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) - ) { - silencer = create_silencer(); - if(!silencer) { - error("Cannot add a new silencer to Netdata"); - return NULL; - } - } - } - - if (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) { - silencer->alarms = strdupz(value); - silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) { - silencer->charts = strdupz(value); - silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) { - silencer->contexts = strdupz(value); - silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) { - silencer->hosts = strdupz(value); - silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT); - } else if (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) { - silencer->families = strdupz(value); - silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT); - } - - return silencer; -} - -/** - * JSON Read Callback - * - * Callback called by netdata to create the silencer. - * - * @param e the main json structure - * - * @return It always return 0. - */ -int health_silencers_json_read_callback(JSON_ENTRY *e) -{ - switch(e->type) { - case JSON_OBJECT: -#ifndef ENABLE_JSONC - e->callback_function = health_silencers_json_read_callback; - if(e->name && strcmp(e->name,"")) { - // init silencer - debug(D_HEALTH, "JSON: Got object with a name, initializing new silencer for %s",e->name); -#endif - e->callback_data = create_silencer(); - if(e->callback_data) { - health_silencers_add(e->callback_data); - } -#ifndef ENABLE_JSONC - } -#endif - break; - - case JSON_ARRAY: - e->callback_function = health_silencers_json_read_callback; - break; - - case JSON_STRING: - if(!strcmp(e->name,"type")) { - debug(D_HEALTH, "JSON: Processing type=%s",e->data.string); - if (!strcmp(e->data.string,"SILENCE")) silencers->stype = STYPE_SILENCE_NOTIFICATIONS; - else if (!strcmp(e->data.string,"DISABLE")) silencers->stype = STYPE_DISABLE_ALARMS; - } else { - debug(D_HEALTH, "JSON: Adding %s=%s", e->name, e->data.string); - health_silencers_addparam(e->callback_data, e->name, e->data.string); - } - break; - - case JSON_BOOLEAN: - debug(D_HEALTH, "JSON: Processing all_alarms"); - silencers->all_alarms=e->data.boolean?1:0; - break; - - case JSON_NUMBER: - case JSON_NULL: - break; - } - - return 0; -} diff --git a/libnetdata/health/health.h b/libnetdata/health/health.h deleted file mode 100644 index 7d560fe95c..0000000000 --- a/libnetdata/health/health.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef NETDATA_HEALTH_LIB -# define NETDATA_HEALTH_LIB 1 - -# include "../libnetdata.h" - -#define HEALTH_ALARM_KEY "alarm" -#define HEALTH_TEMPLATE_KEY "template" -#define HEALTH_CONTEXT_KEY "context" -#define HEALTH_CHART_KEY "chart" -#define HEALTH_HOST_KEY "hosts" -#define HEALTH_OS_KEY "os" -#define HEALTH_FAMILIES_KEY "families" -#define HEALTH_LOOKUP_KEY "lookup" -#define HEALTH_CALC_KEY "calc" - -typedef struct silencer { - char *alarms; - SIMPLE_PATTERN *alarms_pattern; - - char *hosts; - SIMPLE_PATTERN *hosts_pattern; - - char *contexts; - SIMPLE_PATTERN *contexts_pattern; - - char *charts; - SIMPLE_PATTERN *charts_pattern; - - char *families; - SIMPLE_PATTERN *families_pattern; - - struct silencer *next; -} SILENCER; - -typedef enum silence_type { - STYPE_NONE, - STYPE_DISABLE_ALARMS, - STYPE_SILENCE_NOTIFICATIONS -} SILENCE_TYPE; - -typedef struct silencers { - int all_alarms; - SILENCE_TYPE stype; - SILENCER *silencers; -} SILENCERS; - -SILENCERS *silencers; - -extern SILENCER *create_silencer(void); -extern int health_silencers_json_read_callback(JSON_ENTRY *e); -extern void health_silencers_add(SILENCER *silencer); -extern SILENCER * health_silencers_addparam(SILENCER *silencer, char *key, char *value); - -#endif diff --git a/libnetdata/json/Makefile.am b/libnetdata/json/Makefile.am deleted file mode 100644 index 1cb69ed99a..0000000000 --- a/libnetdata/json/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-or-later - -AUTOMAKE_OPTIONS = subdir-objects -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in - - -dist_noinst_DATA = \ - README.md \ - $(NULL) diff --git a/libnetdata/json/README.md b/libnetdata/json/README.md deleted file mode 100644 index fd6cb0f319..0000000000 --- a/libnetdata/json/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# json - -`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. - -[]() diff --git a/libnetdata/json/jsmn.c b/libnetdata/json/jsmn.c deleted file mode 100644 index c8d9e73db9..0000000000 --- a/libnetdata/json/jsmn.c +++ /dev/null @@ -1,326 +0,0 @@ -#include <stdlib.h> - -#include "jsmn.h" - -/** - * Alloc token - * - * Allocates a fresh unused token from the token pull. - * - * @param parser the controller - * @param tokens the tokens I am working - * @param num_tokens the number total of tokens. - * - * @return it returns the next token to work. - */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, - jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; -#ifdef JSMN_PARENT_LINKS - tok->parent = -1; -#endif - return tok; -} - -/** - * Fill Token - * - * Fills token type and boundaries. - * - * @param token the structure to set the values - * @param type is the token type - * @param start is the first position of the value - * @param end is the end of the value - */ -static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - int start, int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; -} - -/** - * Parse primitive - * - * Fills next available token with JSON primitive. - * - * @param parser is the control structure - * @param js is the json string - * @param type is the token type - */ -static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; - int start; - - start = parser->pos; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { -#ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': -#endif - case '\t' : case '\r' : case '\n' : case ' ' : - case ',' : case ']' : case '}' : - goto found; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } -#ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; -#endif - - found: - if (tokens == NULL) { - parser->pos--; - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - parser->pos--; - return 0; -} - -/** - * Parse string - * - * Fills next token with JSON string. - * - * @param parser is the control structure - * @param js is the json string - * @param len is the js length - * @param tokens is structure with the tokens mapped. - * @param num_tokens is the total number of tokens - * - * @return It returns 0 on success and another integer otherwise - */ -static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; - - int start = parser->pos; - - parser->pos++; - - /* Skip starting quote */ - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; - - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - return 0; - } - - /* Backslash: Quoted symbol expected */ - if (c == '\\') { - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': case '/' : case '\\' : case 'b' : - case 'f' : case 'r' : case 'n' : case 't' : - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - int i = 0; - for(; i < 4 && js[parser->pos] != '\0'; i++) { - /* If it isn't a hex character we have an error */ - if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } - } - parser->pos = start; - return JSMN_ERROR_PART; -} - -/** - * JSMN Parse - * - * Parse JSON string and fill tokens. - * - * @param parser the auxiliar vector used to parser - * @param js the string to parse - * @param len the string length - * @param tokens the place to map the tokens - * @param num_tokens the number of tokens present in the tokens structure. - * - * @return It returns the number of tokens present in the string on success or a negative number otherwise - */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens) { - jsmnerr_t r; - int i; - jsmntok_t *token; - int count = 0; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; - - c = js[parser->pos]; - switch (c) { - case '{': case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) - return JSMN_ERROR_NOMEM; - if (parser->toksuper != -1) { - tokens[parser->toksuper].size++; -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': case ']': - if (tokens == NULL) - break; - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); -#ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - break; - } - token = &tokens[token->parent]; - } -#else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) return JSMN_ERROR_INVAL; - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } -#endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ': - break; -#ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': case '0': case '1' : case '2': case '3' : case '4': - case '5': case '6': case '7' : case '8': case '9': - case 't': case 'f': case 'n' : -#else - /* In non-strict mode every unquoted value is a primitive */ - default: -#endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - -#ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; -#endif - } - } - - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } - } - - return count; -} - -/** - * JSMN Init - * - * Creates a new parser based over a given buffer with an array of tokens - * available. - * - * @param parser is the structure with values to reset - */ -void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; -} \ No newline at end of file diff --git a/libnetdata/json/jsmn.h b/libnetdata/json/jsmn.h deleted file mode 100644 index beff586c66..0000000000 --- a/libnetdata/json/jsmn.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __JSMN_H_ -#define __JSMN_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stddef.h> -/** - * JSON type identifier. Basic types are: - * o Object - * o Array - * o String - * o Other primitive: number, boolean (true/false) or null - */ -typedef enum { - JSMN_PRIMITIVE = 0, - JSMN_OBJECT = 1, - JSMN_ARRAY = 2, - JSMN_STRING = 3 -} jsmntype_t; - -typedef enum { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3, -} jsmnerr_t; - -/** - * JSON token description. - * - * @param type type (object, array, string etc.) - * @param start start position in JSON data string - * @param end end position in JSON data string - */ -typedef struct { - jsmntype_t type; - int start; - int end; - int size; -#ifdef JSMN_PARENT_LINKS - int parent; -#endif -} jsmntok_t; - -/** - * JSON parser. Contains an array of token blocks available. Also stores - * the string being parsed now and current position in that string - */ -typedef struct { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g parent object or array */ -} jsmn_parser; - -/** - * Create JSON parser over an array of tokens - */ -void jsmn_init(jsmn_parser *parser); - -/** - * Run JSON parser. It parses a JSON data string into and array of tokens, each describing - * a single JSON object. - */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens); - -#ifdef __cplusplus -} -#endif - -#endif /* __JSMN_H_ */ \ No newline at end of file diff --git a/libnetdata/json/json.c b/libnetdata/json/json.c deleted file mode 100644 index c9ff39b056..0000000000 --- a/libnetdata/json/json.c +++ /dev/null @@ -1,546 +0,0 @@ -#include "jsmn.h" -#include "../libnetdata.h" -#include "json.h" -#include "libnetdata/libnetdata.h" -#include "../../health/health.h" - -#define JSON_TOKENS 1024 - -int json_tokens = JSON_TOKENS; - -/** - * Json Tokenise - * - * Map the string given inside tokens. - * - * @param js is the string used to create the tokens - * @param len is the string length - * @param count the number of tokens present in the string - * - * @return it returns the json parsed in tokens - */ -#ifdef ENABLE_JSONC -json_object *json_tokenise(char *js) { - if(!js) { - error("JSON: json string is empty."); - return NULL; - } - - json_object *token = json_tokener_parse(js); - if(!token) { - error("JSON: Invalid json string."); - return NULL; - } - - return token; -} -#else -jsmntok_t *json_tokenise(char *js, size_t len, size_t *count) -{ - int n = json_tokens; - if(!js || !len) { - error("JSON: json string is empty."); - return NULL; - } - - jsmn_parser parser; - jsmn_init(&parser); - - jsmntok_t *tokens = mallocz(sizeof(jsmntok_t) * n); - if(!tokens) return NULL; - - int ret = jsmn_parse(&parser, js, len, tokens, n); - while (ret == JSMN_ERROR_NOMEM) { - n *= 2; - jsmntok_t *new = reallocz(tokens, sizeof(jsmntok_t) * n); - if(!new) { - freez(tokens); - return NULL; - } - tokens = new; - ret = jsmn_parse(&parser, js, len, tokens, n); - } - - if (ret == JSMN_ERROR_INVAL) { - error("JSON: Invalid json string."); - freez(tokens); - return NULL; - } - else if (ret == JSMN_ERROR_PART) { - error("JSON: Truncated JSON string."); - freez(tokens); - return NULL; - } - - if(count) *count = (size_t)ret; - - if(json_tokens < n) json_tokens = n; - return tokens; -} -#endif - -/** - * Callback Print - * - * Set callback print case necesary and wrinte an information inside a buffer to write in the log. - * - * @param e a pointer for a structure that has the complete information about json structure. - * - * @return It always return 0 - */ -int json_callback_print(JSON_ENTRY *e) -{ - BUFFER *wb=buffer_create(300); - - buffer_sprintf(wb,"%s = ", e->name); - char txt[50]; - switch(e->type) { - case JSON_OBJECT: - e->callback_function = json_callback_print; - buffer_strcat(wb,"OBJECT"); - break; - - case JSON_ARRAY: - e->callback_function = json_callback_print; - sprintf(txt,"ARRAY[%lu]", e->data.items); - buffer_strcat(wb, txt); - break; - - case JSON_STRING: - buffer_strcat(wb, e->data.string); - break; - - case JSON_NUMBER: - sprintf(txt,"%Lf", e->data.number); - buffer_strcat(wb,txt); - - break; - - case JSON_BOOLEAN: - buffer_strcat(wb, e->data.boolean?"TRUE":"FALSE"); - break; - - case JSON_NULL: - buffer_strcat(wb,"NULL"); - break; - } - info("JSON: %s", buffer_tostring(wb)); - buffer_free(wb); - return 0; -} - -/** - * JSONC Set String - * - * Set the string value of the structure JSON_ENTRY. - * - * @param e the output structure - */ -static inline void json_jsonc_set_string(JSON_ENTRY *e,char *key,const char *value) { - size_t length = strlen(key); - e->type = JSON_STRING; - memcpy(e->name,key,length); - e->name[length] = 0x00; - e->data.string = (char *) value; -} - - -#ifdef ENABLE_JSONC -/** - * JSONC set Boolean - * - * Set the boolean value of the structure JSON_ENTRY - * - * @param e the output structure - * @param value the input value - */ -static inline void json_jsonc_set_boolean(JSON_ENTRY *e,int value) { - e->type = JSON_BOOLEAN; - e->data.boolean = value; -} - -/** - * Parse Array - * - * Parse the array object. - * - * @param ptr the pointer for the object that we will parse. - * @param callback_data additional data to be used together the callback function - * @param callback_function function used to create a silencer. - */ -static inline void json_jsonc_parse_array(json_object *ptr, void *callback_data,int (*callback_function)(struct json_entry *)) { - int end = json_object_array_length(ptr); - JSON_ENTRY e; - - if(end) { - int i; - i = 0; - - enum json_type type; - do { - json_object *jvalue = json_object_array_get_idx(ptr, i); - if(jvalue) { - e.callback_data = callback_data; - e.type = JSON_OBJECT; - callback_function(&e); - json_object_object_foreach(jvalue, key, val) { - type = json_object_get_type(val); - if (type == json_type_array) { - e.type = JSON_ARRAY; - json_jsonc_parse_array(val, callback_data, callback_function); - } else if (type == json_type_object) { - json_walk(val,callback_data,callback_function); - } else if (type == json_type_string) { - json_jsonc_set_string(&e,key,json_object_get_string(val)); - callback_function(&e); - } else if (type == json_type_boolean) { - json_jsonc_set_boolean(&e,json_object_get_boolean(val)); - callback_function(&e); - } - } - } - - } while (++i < end); - } -} -#else - -/** - * Walk string - * - * Set JSON_ENTRY to string and map the values from jsmntok_t. - * - * @param js the original string - * @param t the tokens - * @param start the first position - * @param e the output structure. - * - * @return It always return 1 - */ -size_t json_walk_string(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e) -{ - char old = js[t[start].end]; - js[t[start].end] = '\0'; - e->original_string = &js[t[start].start]; - - e->type = JSON_STRING; - e->data.string = e->original_string; - if(e->callback_function) e->callback_function(e); - js[t[start].end] = old; - return 1; -} - -/** - * Walk Primitive - * - * Define the data type of the string - * - * @param js the original string - * @param t the tokens - * @param start the first position - * @param e the output structure. - * - * @return It always return 1 - */ -size_t json_walk_primitive(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e) -{ - char old = js[t[start].end]; - js[t[start].end] = '\0'; - e->original_string = &js[t[start].start]; - - switch(e->original_string[0]) { - case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - case '8': case '9': case '-': case '.': - e->type = JSON_NUMBER; - e->data.number = strtold(e->original_string, NULL); - break; - - case 't': case 'T': - e->type = JSON_BOOLEAN; - e->data.boolean = 1; - break; - - case 'f': case 'F': - e->type = JSON_BOOLEAN; - e->data.boolean = 0; - break; - - case 'n': case 'N': - default: - e->type = JSON_NULL; - break; - } - if(e->callback_function) e->callback_function(e); - js[t[start].end] = old; - return 1; -} - -/** - * Array - * - * Measure the array length - * - * @param js the original string - * @param t the tokens - * @param nest the length of structure t - * @param start the first position - * @param e the output structure. - * - * @return It returns the array length - */ -size_t json_walk_array(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e) -{ - JSON_ENTRY ne = { - .name = "", - .fullname = "", - .callback_data = NULL, - .callback_function = NULL - }; - - char old = js[t[start].end]; - js[t[start].end] = '\0'; - ne.original_string = &js[t[start].start]; - - memcpy(&ne, e, sizeof(JSON_ENTRY)); - ne.type = JSON_ARRAY; - ne.data.items = t[start].size; - ne.callback_function = NULL; - ne.name[0]='\0'; - ne.fullname[0]='\0'; - if(e->callback_function) e->callback_function(&ne); - js[t[start].end] = old; - - size_t i, init = start, size = t[start].size; - - start++; - for(i = 0; i < size ; i++) { - ne.pos = i; - if (!e->name || !e->fullname || strlen(e->name) > JSON_NAME_LEN - 24 || strlen(e->fullname) > JSON_FULLNAME_LEN -24) { - info("JSON: JSON walk_array ignoring element with name:%s fullname:%s",e->name, e->fullname); - continue; - } - sprintf(ne.name, "%s[%lu]", e->name, i); - sprintf(ne.fullname, "%s[%lu]", e->fullname, i); - - switch(t[start].type) { - case JSMN_PRIMITIVE: - start += json_walk_primitive(js, t, start, &ne); - break; - - case JSMN_OBJECT: - start += json_walk_object(js, t, nest + 1, start, &ne); - break; - - case JSMN_ARRAY: - start += json_walk_array(js, t, nest + 1, start, &ne); - break; - - case JSMN_STRING: - start += json_walk_string(js, t, start, &ne); - break; - } - } - return start - init; -} - -/** - * Object - * - * Measure the Object length - * - * @param js the original string - * @param t the tokens - * @param nest the length of structure t - * @param start the first position - * @param e the output structure. - * - * @return It returns the Object length - */ -size_t json_walk_object(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e) -{ - JSON_ENTRY ne = { - .name = "", - .fullname = "", - .callback_data = NULL, - .callback_function = NULL - }; - - char old = js[t[start].end]; - js[t[start].end] = '\0'; - ne.original_string = &js[t[start].start]; - memcpy(&ne, e, sizeof(JSON_ENTRY)); - ne.type = JSON_OBJECT; - ne.callback_function = NULL; - if(e->callback_function) e->callback_function(&ne); - js[t[start].end] = old; - - int key = 1; - size_t i, init = start, size = t[start].size; - - start++; - for(i = 0; i < size ; i++) { - switch(t[start].type) { - case JSMN_PRIMITIVE: - start += json_walk_primitive(js, t, start, &ne); - key = 1; - break; - - case JSMN_OBJECT: - start += json_walk_object(js, t, nest + 1, start, &ne); - key = 1; - break; - - case JSMN_ARRAY: - start += json_walk_array(js, t, nest + 1, start, &ne); - key = 1; - break; - - case JSMN_STRING: - default: - if(key) { - int len = t[start].end - t[start].start; - if (unlikely(len>JSON_NAME_LEN)) len=JSON_NAME_LEN; - strncpy(ne.name, &js[t[start].start], len); - ne.name[len] = '\0'; - len=strlen(e->fullname) + strlen(e->fullname[0]?".":"") + strlen(ne.name); - char *c = mallocz((len+1)*sizeof(char)); - sprintf(c,"%s%s%s", e->fullname, e->fullname[0]?".":"", ne.name); - if (unlikely(len>JSON_FULLNAME_LEN)) len=JSON_FULLNAME_LEN; - strncpy(ne.fullname, c, len); - freez(c); - start++; - key = 0; - } - else { - start += json_walk_string(js, t, start, &ne); - key = 1; - } - break; - } - } - return start - init; -} -#endif - -/** - * Tree - * - * Call the correct walk function according its type. - * - * @param t the json object to work - * @param callback_data additional data to be used together the callback function - * @param callback_function function used to create a silencer. - * - * @return It always return 1 - */ -#ifdef ENABLE_JSONC -size_t json_walk(json_object *t, void *callback_data, int (*callback_function)(struct json_entry *)) { - JSON_ENTRY e; - - e.callback_data = callback_data; - enum json_type type; - json_object_object_foreach(t, key, val) { - type = json_object_get_type(val); - if (type == json_type_array) { - e.type = JSON_ARRAY; - json_jsonc_parse_array(val,NULL,health_silencers_json_read_callback); - } else if (type == json_type_object) { - e.type = JSON_OBJECT; - } else if (type == json_type_string) { - json_jsonc_set_string(&e,key,json_object_get_string(val)); - callback_function(&e); - } else if (type == json_type_boolean) { - json_jsonc_set_boolean(&e,json_object_get_boolean(val)); - callback_function(&e); - } - } - - return 1; -} -#else -/** - * Tree - * - * Call the correct walk function according its type. - * - * @param js the original string - * @param t the tokens - * @param callback_data additional data to be used together the callback function - * @param callback_function function used to create a silencer. - * - * @return It always return 1 - */ -size_t json_walk_tree(char *js, jsmntok_t *t, void *callback_data, int (*callback_function)(struct json_entry *)) -{ - JSON_ENTRY e = { - .name = "", - .fullname = "", - .callback_data = callback_data, - .callback_function = callback_function - }; - - switch (t[0].type) { - case JSMN_OBJECT: - e.type = JSON_OBJECT; - json_walk_object(js, t, 0, 0, &e); - break; - - case JSMN_ARRAY: - e.type = JSON_ARRAY; - json_walk_array(js, t, 0, 0, &e); - break; - - case JSMN_PRIMITIVE: - case JSMN_STRING: - break; - } - - return 1; -} -#endif - -/** - * JSON Parse - * - * Parse the json message with the callback function - * - * @param js the string that the callback function will parse - * @param callback_data additional data to be used together the callback function - * @param callback_function function used to create a silencer. - * - * @return JSON_OK case everything happend as expected, JSON_CANNOT_PARSE case there were errors in the - * parsing procces and JSON_CANNOT_DOWNLOAD case the string given(js) is NULL. - */ -int json_parse(char *js, void *callback_data, int (*callback_function)(JSON_ENTRY *)) -{ - if(js) { -#ifdef ENABLE_JSONC - json_object *tokens = json_tokenise(js); -#else - size_t count; - jsmntok_t *tokens = json_tokenise(js, strlen(js), &count); -#endif - - if(tokens) { -#ifdef ENABLE_JSONC - json_walk(tokens, callback_data, callback_function); - json_object_put(tokens); -#else - json_walk_tree(js, tokens, callback_data, callback_function); - freez(tokens); -#endif - return JSON_OK; - } - - return JSON_CANNOT_PARSE; - } - - return JSON_CANNOT_DOWNLOAD; -} - -/* -int json_test(char *str) -{ - return json_parse(str, NULL, json_callback_print); -} - */ \ No newline at end of file diff --git a/libnetdata/json/json.h b/libnetdata/json/json.h deleted file mode 100644 index 79b58b1704..0000000000 --- a/libnetdata/json/json.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef CHECKIN_JSON_H -#define CHECKIN_JSON_H 1 - - -#if ENABLE_JSONC -# include <json-c/json.h> -#endif - -#include "jsmn.h" - -//https://www.ibm.com/support/knowledgecenter/en/SS9H2Y_7.6.0/com.ibm.dp.doc/json_parserlimits.html -#define JSON_NAME_LEN 256 -#define JSON_FULLNAME_LEN 1024 - -typedef enum { - JSON_OBJECT = 0, - JSON_ARRAY = 1, - JSON_STRING = 2, - JSON_NUMBER = 3, - JSON_BOOLEAN = 4, - JSON_NULL = 5, -} JSON_ENTRY_TYPE; - -typedef struct json_entry { - JSON_ENTRY_TYPE type; - char name[JSON_NAME_LEN + 1]; - char fullname[JSON_FULLNAME_LEN + 1]; - union { - char *string; // type == JSON_STRING - long double number; // type == JSON_NUMBER - int boolean; // type == JSON_BOOLEAN - size_t items; // type == JSON_ARRAY - } data; - size_t pos; // the position of this item in its parent - - char *original_string; - - void *callback_data; - int (*callback_function)(struct json_entry *); -} JSON_ENTRY; - -// ---------------------------------------------------------------------------- -// public functions - -#define JSON_OK 0 -#define JSON_CANNOT_DOWNLOAD 1 -#define JSON_CANNOT_PARSE 2 - -int json_parse(char *js, void *callback_data, int (*callback_function)(JSON_ENTRY *)); - - -// ---------------------------------------------------------------------------- -// private functions - -#ifdef ENABLE_JSONC -json_object *json_tokenise(char *js); -size_t json_walk(json_object *t, void *callback_data, int (*callback_function)(struct json_entry *)); -#else -jsmntok_t *json_tokenise(char *js, size_t len, size_t *count); -size_t json_walk_tree(char *js, jsmntok_t *t, void *callback_data, int (*callback_function)(struct json_entry *)); -#endif - -size_t json_walk_object(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e); -size_t json_walk_array(char *js, jsmntok_t *t, size_t nest, size_t start, JSON_ENTRY *e); -size_t json_walk_string(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e); -size_t json_walk_primitive(char *js, jsmntok_t *t, size_t start, JSON_ENTRY *e); - -int json_callback_print(JSON_ENTRY *e); - - - -#endif \ No newline at end of file diff --git a/libnetdata/libnetdata.h b/libnetdata/libnetdata.h index 43dc1e04dc..41642efd25 100644 --- a/libnetdata/libnetdata.h +++ b/libnetdata/libnetdata.h @@ -310,7 +310,5 @@ extern char *netdata_configured_host_prefix; #include "statistical/statistical.h" #include "adaptive_resortable_list/adaptive_resortable_list.h" #include "url/url.h" -#include "json/json.h" -#include "health/health.h" #endif // NETDATA_LIB_H diff --git a/netdata-installer.sh b/netdata-installer.sh index 9c4d8a76d7..a0c3f828a4 100755 --- a/netdata-installer.sh +++ b/netdata-installer.sh @@ -175,7 +175,6 @@ USAGE: ${PROGRAM} [options] --libs-are-really-here If you get errors about missing zlib or libuuid but you know it is available, you might have a broken pkg-config. Use this option to proceed without checking pkg-config. --disable-telemetry Use this flag to opt-out from our anonymous telemetry progam. - --enable-json Enable to use JSON-C library instead the internal Netdata library. Netdata will by default be compiled with gcc optimization -O2 If you need to pass different CFLAGS, use something like this: @@ -223,7 +222,6 @@ while [ -n "${1}" ]; do "--disable-x86-sse") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-x86-sse/} --disable-x86-sse";; "--disable-telemetry") NETDATA_DISABLE_TELEMETRY=1;; "--disable-go") NETDATA_DISABLE_GO=1;; - "--enable-jsonc") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-jsonc/} --enable-jsonc";; "--install") NETDATA_PREFIX="${2}/netdata" shift 1 diff --git a/tests/health_mgmtapi/expected_list/ALARM_CPU_IOWAIT-list.json b/tests/health_mgmtapi/expected_list/ALARM_CPU_IOWAIT-list.json deleted file mode 100644 index 9f05efe70e..0000000000 --- a/tests/health_mgmtapi/expected_list/ALARM_CPU_IOWAIT-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_iowait" }, { "alarm": "*10min_cpu_usage *load_trigger" } ] } diff --git a/tests/health_mgmtapi/expected_list/ALARM_CPU_USAGE-list.json b/tests/health_mgmtapi/expected_list/ALARM_CPU_USAGE-list.json deleted file mode 100644 index dbf8799252..0000000000 --- a/tests/health_mgmtapi/expected_list/ALARM_CPU_USAGE-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger", "context": "system.cpu" }, { "alarm": "*10min_cpu_usage *load_trigger", "chart": "system.load" } ] } diff --git a/tests/health_mgmtapi/expected_list/CONTEXT_SYSTEM_CPU-list.json b/tests/health_mgmtapi/expected_list/CONTEXT_SYSTEM_CPU-list.json deleted file mode 100644 index a267cfd6fc..0000000000 --- a/tests/health_mgmtapi/expected_list/CONTEXT_SYSTEM_CPU-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "DISABLE", "silencers": [ { "context": "system.cpu" }, { "chart": "system.load" } ] } diff --git a/tests/health_mgmtapi/expected_list/DISABLE-list.json b/tests/health_mgmtapi/expected_list/DISABLE-list.json deleted file mode 100644 index c2c7781043..0000000000 --- a/tests/health_mgmtapi/expected_list/DISABLE-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "DISABLE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] } diff --git a/tests/health_mgmtapi/expected_list/DISABLE_ALL-list.json b/tests/health_mgmtapi/expected_list/DISABLE_ALL-list.json deleted file mode 100644 index bbc3f4f0c9..0000000000 --- a/tests/health_mgmtapi/expected_list/DISABLE_ALL-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": true, "type": "DISABLE", "silencers": [] } diff --git a/tests/health_mgmtapi/expected_list/DISABLE_ALL_ERROR-list.json b/tests/health_mgmtapi/expected_list/DISABLE_ALL_ERROR-list.json deleted file mode 100644 index e8aee17953..0000000000 --- a/tests/health_mgmtapi/expected_list/DISABLE_ALL_ERROR-list.json +++ /dev/null @@ -1 +0,0 @@ -Auth Error diff --git a/tests/health_mgmtapi/expected_list/DISABLE_SYSTEM_LOAD-list.json b/tests/health_mgmtapi/expected_list/DISABLE_SYSTEM_LOAD-list.json deleted file mode 100644 index a7fc1cb8ac..0000000000 --- a/tests/health_mgmtapi/expected_list/DISABLE_SYSTEM_LOAD-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "DISABLE", "silencers": [ { "chart": "system.load" } ] } diff --git a/tests/health_mgmtapi/expected_list/FAMILIES_LOAD-list.json b/tests/health_mgmtapi/expected_list/FAMILIES_LOAD-list.json deleted file mode 100644 index 50119f79c3..0000000000 --- a/tests/health_mgmtapi/expected_list/FAMILIES_LOAD-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "None", "silencers": [ { "families": "load" } ] } diff --git a/tests/health_mgmtapi/expected_list/HOSTS-list.json b/tests/health_mgmtapi/expected_list/HOSTS-list.json deleted file mode 100644 index 9db21b6c34..0000000000 --- a/tests/health_mgmtapi/expected_list/HOSTS-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [ { "hosts": "*" } ] } diff --git a/tests/health_mgmtapi/expected_list/RESET-list.json b/tests/health_mgmtapi/expected_list/RESET-list.json deleted file mode 100644 index 2d3f09d682..0000000000 --- a/tests/health_mgmtapi/expected_list/RESET-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "None", "silencers": [] } diff --git a/tests/health_mgmtapi/expected_list/SILENCE-list.json b/tests/health_mgmtapi/expected_list/SILENCE-list.json deleted file mode 100644 index d157f2d3af..0000000000 --- a/tests/health_mgmtapi/expected_list/SILENCE-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] } diff --git a/tests/health_mgmtapi/expected_list/SILENCE_2-list.json b/tests/health_mgmtapi/expected_list/SILENCE_2-list.json deleted file mode 100644 index d5e6fa2d14..0000000000 --- a/tests/health_mgmtapi/expected_list/SILENCE_2-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [ { "families": "load" } ] } diff --git a/tests/health_mgmtapi/expected_list/SILENCE_3-list.json b/tests/health_mgmtapi/expected_list/SILENCE_3-list.json deleted file mode 100644 index 69e98cc19b..0000000000 --- a/tests/health_mgmtapi/expected_list/SILENCE_3-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [] } WARNING: SILENCE or DISABLE command is ineffective without defining any alarm selectors. diff --git a/tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE-list.json b/tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE-list.json deleted file mode 100644 index dd789cd336..0000000000 --- a/tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger", "chart": "system.load" } ] } diff --git a/tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE_LOAD_TRIGGER-list.json b/tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE_LOAD_TRIGGER-list.json deleted file mode 100644 index d157f2d3af..0000000000 --- a/tests/health_mgmtapi/expected_list/SILENCE_ALARM_CPU_USAGE_LOAD_TRIGGER-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] } diff --git a/tests/health_mgmtapi/expected_list/SILENCE_ALL-list.json b/tests/health_mgmtapi/expected_list/SILENCE_ALL-list.json deleted file mode 100644 index c88ef9fde9..0000000000 --- a/tests/health_mgmtapi/expected_list/SILENCE_ALL-list.json +++ /dev/null @@ -1 +0,0 @@ -{ "all": true, "type": "SILENCE", "silencers": [] } diff --git a/tests/health_mgmtapi/health-cmdapi-test.sh.in b/tests/health_mgmtapi/health-cmdapi-test.sh.in index 5abf2b1704..26279cac97 100755 --- a/tests/health_mgmtapi/health-cmdapi-test.sh.in +++ b/tests/health_mgmtapi/health-cmdapi-test.sh.in @@ -27,7 +27,7 @@ check () { elif [ "${r}" != "${2}" ] ; then echo -e " ${GRAY}WARNING: 'Got ${r}'. Expected '${2}'" iter=$((iter+1)) - if [ $iter -lt 10 ] ; then + if [ $iter -lt 10 ] ; then echo -e " ${GRAY}Repeating test " check "$1" "$2" else @@ -53,20 +53,6 @@ cmd () { fi } -check_list() { - RESPONSE=$(curl -s "http://$URL/api/v1/manage/health?cmd=LIST" -H "X-Auth-Token: $TOKEN" 2>&1) - - NAME="$1-list.json" - echo $RESPONSE > $NAME - diff $NAME expected_list/$NAME 1>/dev/null 2>&1 - if [ $? -eq 0 ]; then - echo -e "${GREEN}Success: The list command got the correct answer for $NAME!" - else - echo -e "${RED}ERROR: the files $NAME and expected_list/$NAME does not match." - exit 1 - fi -} - WHITE='\033[0;37m' RED='\033[0;31m' GREEN='\033[0;32m' @@ -104,13 +90,11 @@ err=0 # Test default state cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" check "Default State" "False False False False False False" - check_list "RESET" # Test auth failure TOKEN="Wrong token" cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_AUTHERROR" check "Default State" "False False False False False False" - check_list "DISABLE_ALL_ERROR" # Set correct token TOKEN="${CORRECT_TOKEN}" @@ -118,107 +102,87 @@ err=0 # Test disable cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_DISABLEALL" check "All disabled" "True False True False True False" - check_list "DISABLE_ALL" # Reset cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" check "Default State" "False False False False False False" - check_list "RESET" # Test silence cmd "cmd=SILENCE ALL" "$HEALTH_CMDAPI_MSG_SILENCEALL" check "All silenced" "False True False True False True" - check_list "SILENCE_ALL" # Reset cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" check "Default State" "False False False False False False" - check_list "RESET" # Add silencer by name printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_ADDED" cmd "cmd=SILENCE&alarm=*10min_cpu_usage *load_trigger" "${resp}" check "Silence notifications for alarm1 and load_trigger" "False True False False False True" - check_list "SILENCE_ALARM_CPU_USAGE_LOAD_TRIGGER" # Convert to disable health checks cmd "cmd=DISABLE" "$HEALTH_CMDAPI_MSG_DISABLE" check "Disable notifications for alarm1 and load_trigger" "True False False False True False" - check_list "DISABLE" # Convert back to silence notifications cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE" check "Silence notifications for alarm1 and load_trigger" "False True False False False True" - check_list "SILENCE" # Add second silencer by name cmd "alarm=*10min_cpu_iowait" "$HEALTH_CMDAPI_MSG_ADDED" check "Silence notifications for alarm1,alarm2 and load_trigger" "False True False True False True" - check_list "ALARM_CPU_IOWAIT" # Reset cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" - check_list "RESET" # Add silencer by chart printf -v resp "$HEALTH_CMDAPI_MSG_DISABLE\n$HEALTH_CMDAPI_MSG_ADDED" cmd "cmd=DISABLE&chart=system.load" "${resp}" check "Default State" "False False False False True False" - check_list "DISABLE_SYSTEM_LOAD" # Add silencer by context cmd "context=system.cpu" "$HEALTH_CMDAPI_MSG_ADDED" check "Default State" "True False True False True False" - check_list "CONTEXT_SYSTEM_CPU" # Reset cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" - check_list "RESET" # Add second condition to a selector (AND) printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_ADDED" cmd "cmd=SILENCE&alarm=*10min_cpu_usage *load_trigger&chart=system.load" "${resp}" check "Silence notifications load_trigger" "False False False False False True" - check_list "SILENCE_ALARM_CPU_USAGE" # Add second selector with two conditions cmd "alarm=*10min_cpu_usage *load_trigger&context=system.cpu" "$HEALTH_CMDAPI_MSG_ADDED" check "Silence notifications load_trigger" "False True False False False True" - check_list "ALARM_CPU_USAGE" # Reset cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" - check_list "RESET" # Add silencer without a command to disable or silence alarms printf -v resp "$HEALTH_CMDAPI_MSG_ADDED\n$HEALTH_CMDAPI_MSG_STYPEWARNING" cmd "families=load" "${resp}" check "Family selector with no command" "False False False False False False" - check_list "FAMILIES_LOAD" # Add silence command cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE" check "Silence family load" "False False False False False True" - check_list "SILENCE_2" # Reset cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" - check_list "RESET" # Add command without silencers printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_NOSELECTORWARNING" cmd "cmd=SILENCE" "${resp}" check "Command with no selector" "False False False False False False" - check_list "SILENCE_3" # Add hosts silencer cmd "hosts=*" "$HEALTH_CMDAPI_MSG_ADDED" check "Silence all hosts" "False True False True False True" - check_list "HOSTS" # Reset cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET" - check_list "RESET" + if [ $err -gt 0 ] ; then echo "$err error(s) found" diff --git a/web/api/health/README.md b/web/api/health/README.md index cc66e82bda..2003a61e04 100644 --- a/web/api/health/README.md +++ b/web/api/health/README.md @@ -45,7 +45,6 @@ The following will return an SVG badge of the alarm named `NAME`, attached to th ## Health Management API 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. -From Netdata v1.16.0 and beyond, the configuration controlled via the API commands is [persisted across netdata restarts](#persistence). Specifically, the API allows you to: - 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 http://localhost/api/v1/manage/health?families=cpu1 cpu2 ``` -### List silencers - -The command `LIST` was added in netdata v1.16.0 and returns a JSON with the current status of the silencers. - -``` - curl "http://myserver/api/v1/manage/health?cmd=LIST" -H "X-Auth-Token: Mytoken" -``` - -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` -``` -json -{ - "all": false, - "type": "SILENCE", - "silencers": [ - { - "alarm": "samplealarm" - }, - { - "context": "random", - "hosts": "myhost" - } - ] -} -``` - -The response below shows that we have disabled all health checks. - -``` -json -{ - "all": true, - "type": "DISABLE", - "silencers": [] -} -``` - ### Responses - "Auth Error" : Token authentication failed @@ -189,21 +151,10 @@ json - "Health checks disabled for alarms matching the selectors" : Added to the response for a cmd=DISABLE - "Alarm notifications silenced for alarms matching the selectors" : Added to the response for a cmd=SILENCE - "Alarm selector added" : Added to the response when a new selector is added +- "Invalid key. Ignoring it." : Wrong name of a parameter. Added to the response and ignored. - "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. - "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. -### Persistence - -From netdata v1.13.1 and beyond, the silencers configuration is persisted to disk and loaded when netdata starts. -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. -The file's location is configurable in `netdata.conf`. The default is shown below: - -``` -[health] - # silencers file = /var/lib/netdata/health.silencers.json -``` - - ### Further reading 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. diff --git a/web/api/health/health_cmdapi.c b/web/api/health/health_cmdapi.c index 5fa0073808..ec177751b9 100644 --- a/web/api/health/health_cmdapi.c +++ b/web/api/health/health_cmdapi.c @@ -1,16 +1,17 @@ // -// Created by Christopher on 11/12/18. +// Created by christopher on 11/12/18. // #include "health_cmdapi.h" -/** - * Free Silencers - * - * Clean the silencer structure - * - * @param t is the structure that will be cleaned. - */ + +static SILENCER *create_silencer(void) { + SILENCER *t = callocz(1, sizeof(SILENCER)); + debug(D_HEALTH, "HEALTH command API: Created empty silencer"); + + return t; +} + void free_silencers(SILENCER *t) { if (!t) return; if (t->next) free_silencers(t->next); @@ -30,104 +31,38 @@ void free_silencers(SILENCER *t) { return; } -/** - * Silencers to JSON Entry - * - * Fill the buffer with the other values given. - * - * @param wb a pointer to the output buffer - * @param var the json variable - * @param val the json value - * @param hasprev has it a previous value? - * - * @return - */ -int health_silencers2json_entry(BUFFER *wb, char* var, char* val, int hasprev) { - if (val) { - buffer_sprintf(wb, "%s\n\t\t\t\"%s\": \"%s\"", (hasprev)?",":"", var, val); - return 1; - } else { - return hasprev; - } -} -/** - * Silencer to JSON - * - * Write the silencer values using JSON format inside a buffer. - * - * @param wb is the buffer to write the silencers. - */ -void health_silencers2json(BUFFER *wb) { - buffer_sprintf(wb, "{\n\t\"all\": %s," - "\n\t\"type\": \"%s\"," - "\n\t\"silencers\": [", - (silencers->all_alarms)?"true":"false", - (silencers->stype == STYPE_NONE)?"None":((silencers->stype == STYPE_DISABLE_ALARMS)?"DISABLE":"SILENCE")); - SILENCER *silencer; - int i = 0, j = 0; - for(silencer = silencers->silencers; silencer ; silencer = silencer->next) { - if(likely(i)) buffer_strcat(wb, ","); - buffer_strcat(wb, "\n\t\t{"); - j=health_silencers2json_entry(wb, HEALTH_ALARM_KEY, silencer->alarms, j); - j=health_silencers2json_entry(wb, HEALTH_CHART_KEY, silencer->charts, j); - j=health_silencers2json_entry(wb, HEALTH_CONTEXT_KEY, silencer->contexts, j); - j=health_silencers2json_entry(wb, HEALTH_HOST_KEY, silencer->hosts, j); - health_silencers2json_entry(wb, HEALTH_FAMILIES_KEY, silencer->families, j); - j=0; - buffer_strcat(wb, "\n\t\t}"); - i++; - } - if(likely(i)) buffer_strcat(wb, "\n\t"); - buffer_strcat(wb, "]\n}\n"); -} - -/** - * Silencer to FILE - * - * Write the sliencer buffer to a file. - * @param wb - */ -void health_silencers2file(BUFFER *wb) { - if (wb->len == 0) return; - - FILE *fd = fopen(silencers_filename, "wb"); - if(fd) { - size_t written = (size_t)fprintf(fd, "%s", wb->buffer) ; - if (written == wb->len ) { - info("Silencer changes written to %s", silencers_filename); - } - fclose(fd); - return; - } - error("Silencer changes could not be written to %s. Error %s", silencers_filename, strerror(errno)); -} - -/** - * Request V1 MGMT Health - * - * Function called by api to management the health. - * - * @param host main structure with client information! - * @param w is the structure with all information of the client request. - * @param url is the url that netdata is working - * - * @return It returns 200 on success and another code otherwise. - */ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, char *url) { int ret = 400; (void) host; + + BUFFER *wb = w->response.data; buffer_flush(wb); wb->contenttype = CT_TEXT_PLAIN; buffer_flush(w->response.data); - //Local instance of the silencer + static uint32_t + hash_alarm = 0, + hash_template = 0, + hash_chart = 0, + hash_context = 0, + hash_host = 0, + hash_families = 0; + + if (unlikely(!hash_alarm)) { + hash_alarm = simple_uhash(HEALTH_ALARM_KEY); + hash_template = simple_uhash(HEALTH_TEMPLATE_KEY); + hash_chart = simple_uhash(HEALTH_CHART_KEY); + hash_context = simple_uhash(HEALTH_CONTEXT_KEY); + hash_host = simple_uhash(HEALTH_HOST_KEY); + hash_families = simple_uhash(HEALTH_FAMILIES_KEY); + } + SILENCER *silencer = NULL; - int config_changed = 1; if (!w->auth_bearer_token) { 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 // name and value are now the parameters if (!strcmp(key, "cmd")) { - //In this "if" we are working with the global silencers. if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) { silencers->all_alarms = 1; silencers->stype = STYPE_SILENCE_NOTIFICATIONS; @@ -171,19 +105,50 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c free_silencers(silencers->silencers); silencers->silencers = NULL; buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET); - } else if (!strcmp(value, HEALTH_CMDAPI_CMD_LIST)) { - w->response.data->contenttype = CT_APPLICATION_JSON; - health_silencers2json(wb); - config_changed=0; } } else { - //In this else we work with local silencer - silencer = health_silencers_addparam(silencer,key,value); - } - } + uint32_t hash = simple_uhash(key); + if (unlikely(silencer == NULL)) { + if ( + (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) || + (hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) || + (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) || + (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) || + (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) || + (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) + ) { + silencer = create_silencer(); + } + } + if (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) { + silencer->alarms = strdupz(value); + silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) { + silencer->charts = strdupz(value); + silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) { + silencer->contexts = strdupz(value); + silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) { + silencer->hosts = strdupz(value); + silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT); + } else if (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) { + silencer->families = strdupz(value); + silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT); + } else { + buffer_strcat(wb, HEALTH_CMDAPI_MSG_INVALID_KEY); + } + } + + } if (likely(silencer)) { - health_silencers_add(silencer); + // Add the created instance to the linked list in silencers + silencer->next = silencers->silencers; + silencers->silencers = silencer; + debug(D_HEALTH, "HEALTH command API: Added silencer %s:%s:%s:%s:%s", silencer->alarms, + silencer->charts, silencer->contexts, silencer->hosts, silencer->families + ); buffer_strcat(wb, HEALTH_CMDAPI_MSG_ADDED); if (silencers->stype == STYPE_NONE) { 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 } w->response.data = wb; buffer_no_cacheable(w->response.data); - if (ret == 200 && config_changed) { - BUFFER *jsonb = buffer_create(200); - health_silencers2json(jsonb); - health_silencers2file(jsonb); - } return ret; } diff --git a/web/api/health/health_cmdapi.h b/web/api/health/health_cmdapi.h index d8ec6aaa02..d0f30401c9 100644 --- a/web/api/health/health_cmdapi.h +++ b/web/api/health/health_cmdapi.h @@ -12,7 +12,6 @@ #define HEALTH_CMDAPI_CMD_SILENCE "SILENCE" #define HEALTH_CMDAPI_CMD_DISABLE "DISABLE" #define HEALTH_CMDAPI_CMD_RESET "RESET" -#define HEALTH_CMDAPI_CMD_LIST "LIST" #define HEALTH_CMDAPI_MSG_AUTHERROR "Auth Error\n" #define HEALTH_CMDAPI_MSG_SILENCEALL "All alarm notifications are silenced\n" @@ -21,6 +20,7 @@ #define HEALTH_CMDAPI_MSG_DISABLE "Health checks disabled for alarms matching the selectors\n" #define HEALTH_CMDAPI_MSG_SILENCE "Alarm notifications silenced for alarms matching the selectors\n" #define HEALTH_CMDAPI_MSG_ADDED "Alarm selector added\n" +#define HEALTH_CMDAPI_MSG_INVALID_KEY "Invalid key. Ignoring it.\n" #define HEALTH_CMDAPI_MSG_STYPEWARNING "WARNING: Added alarm selector to silence/disable alarms without a SILENCE or DISABLE command.\n" #define HEALTH_CMDAPI_MSG_NOSELECTORWARNING "WARNING: SILENCE or DISABLE command is ineffective without defining any alarm selectors.\n" diff --git a/web/api/netdata-swagger.json b/web/api/netdata-swagger.json index 70018730e0..6d28e840a2 100644 --- a/web/api/netdata-swagger.json +++ b/web/api/netdata-swagger.json @@ -664,7 +664,7 @@ { "name": "cmd", "in": "query", - "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.", + "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.", "required": false, "type": "string", "enum": [ @@ -672,8 +672,7 @@ "SILENCE ALL", "DISABLE", "SILENCE", - "RESET", - "LIST" + "RESET" ] }, { diff --git a/web/api/netdata-swagger.yaml b/web/api/netdata-swagger.yaml index 841648d631..9c5517d03a 100644 --- a/web/api/netdata-swagger.yaml +++ b/web/api/netdata-swagger.yaml @@ -437,10 +437,10 @@ paths: parameters: - name: cmd in: query - 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.' + 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.' required: false type: string - enum: ['DISABLE ALL', 'SILENCE ALL', 'DISABLE', 'SILENCE', 'RESET', 'LIST'] + enum: ['DISABLE ALL', 'SILENCE ALL', 'DISABLE', 'SILENCE', 'RESET'] - name: alarm in: query description: 'The expression provided will match both `alarm` and `template` names.'