mirror of
https://github.com/netdata/netdata.git
synced 2025-04-16 18:37:50 +00:00
Revert "Easily disable alarms, by persisting the silencers configuration (#6274)"
This reverts commit 60a73e90de
.
Emergency rollback of potential culprit as per issue #6356
Will be re-merging the change after investigation
This commit is contained in:
parent
5d5266dc1a
commit
171d8f5d01
40 changed files with 126 additions and 1638 deletions
CMakeLists.txtMakefile.amconfigure.ac
health
libnetdata
netdata-installer.shtests/health_mgmtapi
expected_list
ALARM_CPU_IOWAIT-list.jsonALARM_CPU_USAGE-list.jsonCONTEXT_SYSTEM_CPU-list.jsonDISABLE-list.jsonDISABLE_ALL-list.jsonDISABLE_ALL_ERROR-list.jsonDISABLE_SYSTEM_LOAD-list.jsonFAMILIES_LOAD-list.jsonHOSTS-list.jsonRESET-list.jsonSILENCE-list.jsonSILENCE_2-list.jsonSILENCE_3-list.jsonSILENCE_ALARM_CPU_USAGE-list.jsonSILENCE_ALARM_CPU_USAGE_LOAD_TRIGGER-list.jsonSILENCE_ALL-list.json
health-cmdapi-test.sh.inweb/api
|
@ -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_LIBRARIES ${NETDATA_COMMON_LIBRARIES} ${OPENSSL_LIBRARIES})
|
||||||
set(NETDATA_COMMON_INCLUDE_DIRS ${NETDATA_COMMON_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS})
|
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
|
# Detect libcap
|
||||||
|
|
||||||
|
@ -313,15 +305,8 @@ set(LIBNETDATA_FILES
|
||||||
libnetdata/threads/threads.h
|
libnetdata/threads/threads.h
|
||||||
libnetdata/url/url.c
|
libnetdata/url/url.c
|
||||||
libnetdata/url/url.h
|
libnetdata/url/url.h
|
||||||
libnetdata/health/health.c
|
|
||||||
libnetdata/health/health.h
|
|
||||||
libnetdata/socket/security.c
|
libnetdata/socket/security.c
|
||||||
libnetdata/socket/security.h
|
libnetdata/socket/security.h)
|
||||||
libnetdata/json/json.c
|
|
||||||
libnetdata/json/json.h
|
|
||||||
libnetdata/json/jsmn.c
|
|
||||||
libnetdata/json/jsmn.h
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(libnetdata OBJECT ${LIBNETDATA_FILES})
|
add_library(libnetdata OBJECT ${LIBNETDATA_FILES})
|
||||||
|
|
||||||
|
|
12
Makefile.am
12
Makefile.am
|
@ -159,14 +159,8 @@ LIBNETDATA_FILES = \
|
||||||
libnetdata/storage_number/storage_number.h \
|
libnetdata/storage_number/storage_number.h \
|
||||||
libnetdata/threads/threads.c \
|
libnetdata/threads/threads.c \
|
||||||
libnetdata/threads/threads.h \
|
libnetdata/threads/threads.h \
|
||||||
libnetdata/url/url.c \
|
libnetdata/url/url.c \
|
||||||
libnetdata/url/url.h \
|
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 \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
APPS_PLUGIN_FILES = \
|
APPS_PLUGIN_FILES = \
|
||||||
|
@ -512,12 +506,12 @@ endif
|
||||||
NETDATA_COMMON_LIBS = \
|
NETDATA_COMMON_LIBS = \
|
||||||
$(OPTIONAL_MATH_LIBS) \
|
$(OPTIONAL_MATH_LIBS) \
|
||||||
$(OPTIONAL_ZLIB_LIBS) \
|
$(OPTIONAL_ZLIB_LIBS) \
|
||||||
|
$(OPTIONAL_SSL_LIBS) \
|
||||||
$(OPTIONAL_UUID_LIBS) \
|
$(OPTIONAL_UUID_LIBS) \
|
||||||
$(OPTIONAL_UV_LIBS) \
|
$(OPTIONAL_UV_LIBS) \
|
||||||
$(OPTIONAL_LZ4_LIBS) \
|
$(OPTIONAL_LZ4_LIBS) \
|
||||||
$(OPTIONAL_JUDY_LIBS) \
|
$(OPTIONAL_JUDY_LIBS) \
|
||||||
$(OPTIONAL_SSL_LIBS) \
|
$(OPTIONAL_SSL_LIBS) \
|
||||||
$(OPTIONAL_JSONC_LIBS) \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
sbin_PROGRAMS += netdata
|
sbin_PROGRAMS += netdata
|
||||||
|
|
39
configure.ac
39
configure.ac
|
@ -142,12 +142,6 @@ AC_ARG_ENABLE(
|
||||||
,
|
,
|
||||||
[enable_https="detect"]
|
[enable_https="detect"]
|
||||||
)
|
)
|
||||||
AC_ARG_ENABLE(
|
|
||||||
[jsonc],
|
|
||||||
[AS_HELP_STRING([--enable-jsonc], [Enable JSON-C support @<:@default autodetect@:>@])],
|
|
||||||
,
|
|
||||||
[enable_jsonc="detect"]
|
|
||||||
)
|
|
||||||
AC_ARG_ENABLE(
|
AC_ARG_ENABLE(
|
||||||
[dbengine],
|
[dbengine],
|
||||||
[AS_HELP_STRING([--disable-dbengine], [disable netdata dbengine @<:@default autodetect@:>@])],
|
[AS_HELP_STRING([--disable-dbengine], [disable netdata dbengine @<:@default autodetect@:>@])],
|
||||||
|
@ -353,20 +347,6 @@ AC_CHECK_LIB(
|
||||||
OPTIONAL_SSL_CFLAGS="${SSL_CFLAGS}"
|
OPTIONAL_SSL_CFLAGS="${SSL_CFLAGS}"
|
||||||
OPTIONAL_SSL_LIBS="${SSL_LIBS}"
|
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
|
# DB engine and HTTPS
|
||||||
test "${enable_dbengine}" = "yes" -a -z "${UV_LIBS}" && \
|
test "${enable_dbengine}" = "yes" -a -z "${UV_LIBS}" && \
|
||||||
|
@ -401,22 +381,6 @@ fi
|
||||||
AC_MSG_RESULT([${enable_https}])
|
AC_MSG_RESULT([${enable_https}])
|
||||||
AM_CONDITIONAL([ENABLE_HTTPS], [test "${enable_https}" = "yes"])
|
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
|
# compiler options
|
||||||
|
|
||||||
|
@ -1011,7 +975,6 @@ AC_SUBST([OPTIONAL_UV_LIBS])
|
||||||
AC_SUBST([OPTIONAL_LZ4_LIBS])
|
AC_SUBST([OPTIONAL_LZ4_LIBS])
|
||||||
AC_SUBST([OPTIONAL_JUDY_LIBS])
|
AC_SUBST([OPTIONAL_JUDY_LIBS])
|
||||||
AC_SUBST([OPTIONAL_SSL_LIBS])
|
AC_SUBST([OPTIONAL_SSL_LIBS])
|
||||||
AC_SUBST([OPTIONAL_JSONC_LIBS])
|
|
||||||
AC_SUBST([OPTIONAL_NFACCT_CFLAGS])
|
AC_SUBST([OPTIONAL_NFACCT_CFLAGS])
|
||||||
AC_SUBST([OPTIONAL_NFACCT_LIBS])
|
AC_SUBST([OPTIONAL_NFACCT_LIBS])
|
||||||
AC_SUBST([OPTIONAL_ZLIB_CFLAGS])
|
AC_SUBST([OPTIONAL_ZLIB_CFLAGS])
|
||||||
|
@ -1078,8 +1041,6 @@ AC_CONFIG_FILES([
|
||||||
libnetdata/config/Makefile
|
libnetdata/config/Makefile
|
||||||
libnetdata/dictionary/Makefile
|
libnetdata/dictionary/Makefile
|
||||||
libnetdata/eval/Makefile
|
libnetdata/eval/Makefile
|
||||||
libnetdata/json/Makefile
|
|
||||||
libnetdata/health/Makefile
|
|
||||||
libnetdata/locks/Makefile
|
libnetdata/locks/Makefile
|
||||||
libnetdata/log/Makefile
|
libnetdata/log/Makefile
|
||||||
libnetdata/popen/Makefile
|
libnetdata/popen/Makefile
|
||||||
|
|
101
health/health.c
101
health/health.c
|
@ -1,6 +1,5 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include <libnetdata/json/json.h>
|
|
||||||
#include "health.h"
|
#include "health.h"
|
||||||
|
|
||||||
struct health_cmdapi_thread_status {
|
struct health_cmdapi_thread_status {
|
||||||
|
@ -14,79 +13,18 @@ unsigned int default_health_enabled = 1;
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// health initialization
|
// 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) {
|
inline char *health_user_config_dir(void) {
|
||||||
char buffer[FILENAME_MAX + 1];
|
char buffer[FILENAME_MAX + 1];
|
||||||
snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_user_config_dir);
|
snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_user_config_dir);
|
||||||
return config_get(CONFIG_SECTION_HEALTH, "health configuration directory", buffer);
|
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) {
|
inline char *health_stock_config_dir(void) {
|
||||||
char buffer[FILENAME_MAX + 1];
|
char buffer[FILENAME_MAX + 1];
|
||||||
snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_stock_config_dir);
|
snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_stock_config_dir);
|
||||||
return config_get(CONFIG_SECTION_HEALTH, "stock health configuration directory", buffer);
|
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) {
|
void health_init(void) {
|
||||||
debug(D_HEALTH, "Health configuration initializing");
|
debug(D_HEALTH, "Health configuration initializing");
|
||||||
|
|
||||||
|
@ -94,20 +32,11 @@ void health_init(void) {
|
||||||
debug(D_HEALTH, "Health is disabled.");
|
debug(D_HEALTH, "Health is disabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
health_silencers_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// re-load health configuration
|
// 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) {
|
void health_reload_host(RRDHOST *host) {
|
||||||
if(unlikely(!host->health_enabled))
|
if(unlikely(!host->health_enabled))
|
||||||
return;
|
return;
|
||||||
|
@ -155,11 +84,6 @@ void health_reload_host(RRDHOST *host) {
|
||||||
rrdhost_unlock(host);
|
rrdhost_unlock(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reload
|
|
||||||
*
|
|
||||||
* Reload the host configuration for all hosts.
|
|
||||||
*/
|
|
||||||
void health_reload(void) {
|
void health_reload(void) {
|
||||||
|
|
||||||
rrd_rdlock();
|
rrd_rdlock();
|
||||||
|
@ -501,16 +425,6 @@ SILENCE_TYPE check_silenced(RRDCALC *rc, char* host, SILENCERS *silencers) {
|
||||||
return STYPE_NONE;
|
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) {
|
int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) {
|
||||||
uint32_t rrdcalc_flags_old = rc->rrdcalc_flags;
|
uint32_t rrdcalc_flags_old = rc->rrdcalc_flags;
|
||||||
// Clear the flags
|
// Clear the flags
|
||||||
|
@ -540,15 +454,6 @@ int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) {
|
||||||
return 0;
|
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) {
|
void *health_main(void *ptr) {
|
||||||
netdata_thread_cleanup_push(health_main_cleanup, ptr);
|
netdata_thread_cleanup_push(health_main_cleanup, ptr);
|
||||||
|
|
||||||
|
@ -560,6 +465,11 @@ void *health_main(void *ptr) {
|
||||||
|
|
||||||
unsigned int loop = 0;
|
unsigned int loop = 0;
|
||||||
|
|
||||||
|
silencers = mallocz(sizeof(SILENCERS));
|
||||||
|
silencers->all_alarms=0;
|
||||||
|
silencers->stype=STYPE_NONE;
|
||||||
|
silencers->silencers=NULL;
|
||||||
|
|
||||||
while(!netdata_exit) {
|
while(!netdata_exit) {
|
||||||
loop++;
|
loop++;
|
||||||
debug(D_HEALTH, "Health monitoring iteration no %u started", 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
|
// the first loop is to lookup values from the db
|
||||||
for (rc = host->alarms; rc; rc = rc->next) {
|
for (rc = host->alarms; rc; rc = rc->next) {
|
||||||
|
|
||||||
//case it is disabled I will get the next rc
|
|
||||||
if (update_disabled_silenced(host, rc))
|
if (update_disabled_silenced(host, rc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,16 @@ extern unsigned int default_health_enabled;
|
||||||
#define HEALTH_LISTEN_BACKLOG 4096
|
#define HEALTH_LISTEN_BACKLOG 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define HEALTH_ALARM_KEY "alarm"
|
||||||
|
#define HEALTH_TEMPLATE_KEY "template"
|
||||||
#define HEALTH_ON_KEY "on"
|
#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_EVERY_KEY "every"
|
||||||
#define HEALTH_GREEN_KEY "green"
|
#define HEALTH_GREEN_KEY "green"
|
||||||
#define HEALTH_RED_KEY "red"
|
#define HEALTH_RED_KEY "red"
|
||||||
|
@ -50,9 +57,38 @@ extern unsigned int default_health_enabled;
|
||||||
#define HEALTH_DELAY_KEY "delay"
|
#define HEALTH_DELAY_KEY "delay"
|
||||||
#define HEALTH_OPTIONS_KEY "options"
|
#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_init(void);
|
||||||
extern void *health_main(void *ptr);
|
extern void *health_main(void *ptr);
|
||||||
|
|
|
@ -481,7 +481,7 @@ static int health_readfile(const char *filename, void *data) {
|
||||||
if(append < HEALTH_CONF_MAX_LINE)
|
if(append < HEALTH_CONF_MAX_LINE)
|
||||||
continue;
|
continue;
|
||||||
else {
|
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;
|
append = 0;
|
||||||
|
|
|
@ -21,8 +21,6 @@ SUBDIRS = \
|
||||||
storage_number \
|
storage_number \
|
||||||
threads \
|
threads \
|
||||||
url \
|
url \
|
||||||
json \
|
|
||||||
health \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
dist_noinst_DATA = \
|
dist_noinst_DATA = \
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = subdir-objects
|
|
||||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
|
||||||
|
|
||||||
|
|
||||||
dist_noinst_DATA = \
|
|
||||||
$(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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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.
|
|
||||||
|
|
||||||
[]()
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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_ */
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -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
|
|
|
@ -310,7 +310,5 @@ extern char *netdata_configured_host_prefix;
|
||||||
#include "statistical/statistical.h"
|
#include "statistical/statistical.h"
|
||||||
#include "adaptive_resortable_list/adaptive_resortable_list.h"
|
#include "adaptive_resortable_list/adaptive_resortable_list.h"
|
||||||
#include "url/url.h"
|
#include "url/url.h"
|
||||||
#include "json/json.h"
|
|
||||||
#include "health/health.h"
|
|
||||||
|
|
||||||
#endif // NETDATA_LIB_H
|
#endif // NETDATA_LIB_H
|
||||||
|
|
|
@ -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
|
--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.
|
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.
|
--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
|
Netdata will by default be compiled with gcc optimization -O2
|
||||||
If you need to pass different CFLAGS, use something like this:
|
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-x86-sse") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-x86-sse/} --disable-x86-sse";;
|
||||||
"--disable-telemetry") NETDATA_DISABLE_TELEMETRY=1;;
|
"--disable-telemetry") NETDATA_DISABLE_TELEMETRY=1;;
|
||||||
"--disable-go") NETDATA_DISABLE_GO=1;;
|
"--disable-go") NETDATA_DISABLE_GO=1;;
|
||||||
"--enable-jsonc") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-jsonc/} --enable-jsonc";;
|
|
||||||
"--install")
|
"--install")
|
||||||
NETDATA_PREFIX="${2}/netdata"
|
NETDATA_PREFIX="${2}/netdata"
|
||||||
shift 1
|
shift 1
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_iowait" }, { "alarm": "*10min_cpu_usage *load_trigger" } ] }
|
|
|
@ -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" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "DISABLE", "silencers": [ { "context": "system.cpu" }, { "chart": "system.load" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "DISABLE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": true, "type": "DISABLE", "silencers": [] }
|
|
|
@ -1 +0,0 @@
|
||||||
Auth Error
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "DISABLE", "silencers": [ { "chart": "system.load" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "None", "silencers": [ { "families": "load" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "SILENCE", "silencers": [ { "hosts": "*" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "None", "silencers": [] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "SILENCE", "silencers": [ { "families": "load" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "SILENCE", "silencers": [] } WARNING: SILENCE or DISABLE command is ineffective without defining any alarm selectors.
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger", "chart": "system.load" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": false, "type": "SILENCE", "silencers": [ { "alarm": "*10min_cpu_usage *load_trigger" } ] }
|
|
|
@ -1 +0,0 @@
|
||||||
{ "all": true, "type": "SILENCE", "silencers": [] }
|
|
|
@ -27,7 +27,7 @@ check () {
|
||||||
elif [ "${r}" != "${2}" ] ; then
|
elif [ "${r}" != "${2}" ] ; then
|
||||||
echo -e " ${GRAY}WARNING: 'Got ${r}'. Expected '${2}'"
|
echo -e " ${GRAY}WARNING: 'Got ${r}'. Expected '${2}'"
|
||||||
iter=$((iter+1))
|
iter=$((iter+1))
|
||||||
if [ $iter -lt 10 ] ; then
|
if [ $iter -lt 10 ] ; then
|
||||||
echo -e " ${GRAY}Repeating test "
|
echo -e " ${GRAY}Repeating test "
|
||||||
check "$1" "$2"
|
check "$1" "$2"
|
||||||
else
|
else
|
||||||
|
@ -53,20 +53,6 @@ cmd () {
|
||||||
fi
|
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'
|
WHITE='\033[0;37m'
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
|
@ -104,13 +90,11 @@ err=0
|
||||||
# Test default state
|
# Test default state
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check "Default State" "False False False False False False"
|
check "Default State" "False False False False False False"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
# Test auth failure
|
# Test auth failure
|
||||||
TOKEN="Wrong token"
|
TOKEN="Wrong token"
|
||||||
cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_AUTHERROR"
|
cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_AUTHERROR"
|
||||||
check "Default State" "False False False False False False"
|
check "Default State" "False False False False False False"
|
||||||
check_list "DISABLE_ALL_ERROR"
|
|
||||||
|
|
||||||
# Set correct token
|
# Set correct token
|
||||||
TOKEN="${CORRECT_TOKEN}"
|
TOKEN="${CORRECT_TOKEN}"
|
||||||
|
@ -118,107 +102,87 @@ err=0
|
||||||
# Test disable
|
# Test disable
|
||||||
cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_DISABLEALL"
|
cmd "cmd=DISABLE ALL" "$HEALTH_CMDAPI_MSG_DISABLEALL"
|
||||||
check "All disabled" "True False True False True False"
|
check "All disabled" "True False True False True False"
|
||||||
check_list "DISABLE_ALL"
|
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check "Default State" "False False False False False False"
|
check "Default State" "False False False False False False"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
# Test silence
|
# Test silence
|
||||||
cmd "cmd=SILENCE ALL" "$HEALTH_CMDAPI_MSG_SILENCEALL"
|
cmd "cmd=SILENCE ALL" "$HEALTH_CMDAPI_MSG_SILENCEALL"
|
||||||
check "All silenced" "False True False True False True"
|
check "All silenced" "False True False True False True"
|
||||||
check_list "SILENCE_ALL"
|
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check "Default State" "False False False False False False"
|
check "Default State" "False False False False False False"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
# Add silencer by name
|
# Add silencer by name
|
||||||
printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_ADDED"
|
printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_ADDED"
|
||||||
cmd "cmd=SILENCE&alarm=*10min_cpu_usage *load_trigger" "${resp}"
|
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 "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
|
# Convert to disable health checks
|
||||||
cmd "cmd=DISABLE" "$HEALTH_CMDAPI_MSG_DISABLE"
|
cmd "cmd=DISABLE" "$HEALTH_CMDAPI_MSG_DISABLE"
|
||||||
check "Disable notifications for alarm1 and load_trigger" "True False False False True False"
|
check "Disable notifications for alarm1 and load_trigger" "True False False False True False"
|
||||||
check_list "DISABLE"
|
|
||||||
|
|
||||||
# Convert back to silence notifications
|
# Convert back to silence notifications
|
||||||
cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE"
|
cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE"
|
||||||
check "Silence notifications for alarm1 and load_trigger" "False True False False False True"
|
check "Silence notifications for alarm1 and load_trigger" "False True False False False True"
|
||||||
check_list "SILENCE"
|
|
||||||
|
|
||||||
# Add second silencer by name
|
# Add second silencer by name
|
||||||
cmd "alarm=*10min_cpu_iowait" "$HEALTH_CMDAPI_MSG_ADDED"
|
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 "Silence notifications for alarm1,alarm2 and load_trigger" "False True False True False True"
|
||||||
check_list "ALARM_CPU_IOWAIT"
|
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
# Add silencer by chart
|
# Add silencer by chart
|
||||||
printf -v resp "$HEALTH_CMDAPI_MSG_DISABLE\n$HEALTH_CMDAPI_MSG_ADDED"
|
printf -v resp "$HEALTH_CMDAPI_MSG_DISABLE\n$HEALTH_CMDAPI_MSG_ADDED"
|
||||||
cmd "cmd=DISABLE&chart=system.load" "${resp}"
|
cmd "cmd=DISABLE&chart=system.load" "${resp}"
|
||||||
check "Default State" "False False False False True False"
|
check "Default State" "False False False False True False"
|
||||||
check_list "DISABLE_SYSTEM_LOAD"
|
|
||||||
|
|
||||||
# Add silencer by context
|
# Add silencer by context
|
||||||
cmd "context=system.cpu" "$HEALTH_CMDAPI_MSG_ADDED"
|
cmd "context=system.cpu" "$HEALTH_CMDAPI_MSG_ADDED"
|
||||||
check "Default State" "True False True False True False"
|
check "Default State" "True False True False True False"
|
||||||
check_list "CONTEXT_SYSTEM_CPU"
|
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
# Add second condition to a selector (AND)
|
# Add second condition to a selector (AND)
|
||||||
printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_ADDED"
|
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}"
|
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 "Silence notifications load_trigger" "False False False False False True"
|
||||||
check_list "SILENCE_ALARM_CPU_USAGE"
|
|
||||||
|
|
||||||
# Add second selector with two conditions
|
# Add second selector with two conditions
|
||||||
cmd "alarm=*10min_cpu_usage *load_trigger&context=system.cpu" "$HEALTH_CMDAPI_MSG_ADDED"
|
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 "Silence notifications load_trigger" "False True False False False True"
|
||||||
check_list "ALARM_CPU_USAGE"
|
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
# Add silencer without a command to disable or silence alarms
|
# Add silencer without a command to disable or silence alarms
|
||||||
printf -v resp "$HEALTH_CMDAPI_MSG_ADDED\n$HEALTH_CMDAPI_MSG_STYPEWARNING"
|
printf -v resp "$HEALTH_CMDAPI_MSG_ADDED\n$HEALTH_CMDAPI_MSG_STYPEWARNING"
|
||||||
cmd "families=load" "${resp}"
|
cmd "families=load" "${resp}"
|
||||||
check "Family selector with no command" "False False False False False False"
|
check "Family selector with no command" "False False False False False False"
|
||||||
check_list "FAMILIES_LOAD"
|
|
||||||
|
|
||||||
# Add silence command
|
# Add silence command
|
||||||
cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE"
|
cmd "cmd=SILENCE" "$HEALTH_CMDAPI_MSG_SILENCE"
|
||||||
check "Silence family load" "False False False False False True"
|
check "Silence family load" "False False False False False True"
|
||||||
check_list "SILENCE_2"
|
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
# Add command without silencers
|
# Add command without silencers
|
||||||
printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_NOSELECTORWARNING"
|
printf -v resp "$HEALTH_CMDAPI_MSG_SILENCE\n$HEALTH_CMDAPI_MSG_NOSELECTORWARNING"
|
||||||
cmd "cmd=SILENCE" "${resp}"
|
cmd "cmd=SILENCE" "${resp}"
|
||||||
check "Command with no selector" "False False False False False False"
|
check "Command with no selector" "False False False False False False"
|
||||||
check_list "SILENCE_3"
|
|
||||||
|
|
||||||
# Add hosts silencer
|
# Add hosts silencer
|
||||||
cmd "hosts=*" "$HEALTH_CMDAPI_MSG_ADDED"
|
cmd "hosts=*" "$HEALTH_CMDAPI_MSG_ADDED"
|
||||||
check "Silence all hosts" "False True False True False True"
|
check "Silence all hosts" "False True False True False True"
|
||||||
check_list "HOSTS"
|
|
||||||
|
|
||||||
# Reset
|
# Reset
|
||||||
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
cmd "cmd=RESET" "$HEALTH_CMDAPI_MSG_RESET"
|
||||||
check_list "RESET"
|
|
||||||
|
|
||||||
if [ $err -gt 0 ] ; then
|
if [ $err -gt 0 ] ; then
|
||||||
echo "$err error(s) found"
|
echo "$err error(s) found"
|
||||||
|
|
|
@ -45,7 +45,6 @@ The following will return an SVG badge of the alarm named `NAME`, attached to th
|
||||||
## Health Management API
|
## 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.
|
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:
|
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.
|
- 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
|
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
|
### Responses
|
||||||
|
|
||||||
- "Auth Error" : Token authentication failed
|
- "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
|
- "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 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
|
- "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: 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.
|
- "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
|
### 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.
|
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.
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
//
|
//
|
||||||
// Created by Christopher on 11/12/18.
|
// Created by christopher on 11/12/18.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "health_cmdapi.h"
|
#include "health_cmdapi.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* Free Silencers
|
static SILENCER *create_silencer(void) {
|
||||||
*
|
SILENCER *t = callocz(1, sizeof(SILENCER));
|
||||||
* Clean the silencer structure
|
debug(D_HEALTH, "HEALTH command API: Created empty silencer");
|
||||||
*
|
|
||||||
* @param t is the structure that will be cleaned.
|
return t;
|
||||||
*/
|
}
|
||||||
|
|
||||||
void free_silencers(SILENCER *t) {
|
void free_silencers(SILENCER *t) {
|
||||||
if (!t) return;
|
if (!t) return;
|
||||||
if (t->next) free_silencers(t->next);
|
if (t->next) free_silencers(t->next);
|
||||||
|
@ -30,104 +31,38 @@ void free_silencers(SILENCER *t) {
|
||||||
return;
|
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 web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, char *url) {
|
||||||
int ret = 400;
|
int ret = 400;
|
||||||
(void) host;
|
(void) host;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BUFFER *wb = w->response.data;
|
BUFFER *wb = w->response.data;
|
||||||
buffer_flush(wb);
|
buffer_flush(wb);
|
||||||
wb->contenttype = CT_TEXT_PLAIN;
|
wb->contenttype = CT_TEXT_PLAIN;
|
||||||
|
|
||||||
buffer_flush(w->response.data);
|
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;
|
SILENCER *silencer = NULL;
|
||||||
int config_changed = 1;
|
|
||||||
|
|
||||||
if (!w->auth_bearer_token) {
|
if (!w->auth_bearer_token) {
|
||||||
buffer_strcat(wb, HEALTH_CMDAPI_MSG_AUTHERROR);
|
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
|
// name and value are now the parameters
|
||||||
if (!strcmp(key, "cmd")) {
|
if (!strcmp(key, "cmd")) {
|
||||||
//In this "if" we are working with the global silencers.
|
|
||||||
if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) {
|
if (!strcmp(value, HEALTH_CMDAPI_CMD_SILENCEALL)) {
|
||||||
silencers->all_alarms = 1;
|
silencers->all_alarms = 1;
|
||||||
silencers->stype = STYPE_SILENCE_NOTIFICATIONS;
|
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);
|
free_silencers(silencers->silencers);
|
||||||
silencers->silencers = NULL;
|
silencers->silencers = NULL;
|
||||||
buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET);
|
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 {
|
} else {
|
||||||
//In this else we work with local silencer
|
uint32_t hash = simple_uhash(key);
|
||||||
silencer = health_silencers_addparam(silencer,key,value);
|
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)) {
|
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);
|
buffer_strcat(wb, HEALTH_CMDAPI_MSG_ADDED);
|
||||||
if (silencers->stype == STYPE_NONE) {
|
if (silencers->stype == STYPE_NONE) {
|
||||||
buffer_strcat(wb, HEALTH_CMDAPI_MSG_STYPEWARNING);
|
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;
|
w->response.data = wb;
|
||||||
buffer_no_cacheable(w->response.data);
|
buffer_no_cacheable(w->response.data);
|
||||||
if (ret == 200 && config_changed) {
|
|
||||||
BUFFER *jsonb = buffer_create(200);
|
|
||||||
health_silencers2json(jsonb);
|
|
||||||
health_silencers2file(jsonb);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#define HEALTH_CMDAPI_CMD_SILENCE "SILENCE"
|
#define HEALTH_CMDAPI_CMD_SILENCE "SILENCE"
|
||||||
#define HEALTH_CMDAPI_CMD_DISABLE "DISABLE"
|
#define HEALTH_CMDAPI_CMD_DISABLE "DISABLE"
|
||||||
#define HEALTH_CMDAPI_CMD_RESET "RESET"
|
#define HEALTH_CMDAPI_CMD_RESET "RESET"
|
||||||
#define HEALTH_CMDAPI_CMD_LIST "LIST"
|
|
||||||
|
|
||||||
#define HEALTH_CMDAPI_MSG_AUTHERROR "Auth Error\n"
|
#define HEALTH_CMDAPI_MSG_AUTHERROR "Auth Error\n"
|
||||||
#define HEALTH_CMDAPI_MSG_SILENCEALL "All alarm notifications are silenced\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_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_SILENCE "Alarm notifications silenced for alarms matching the selectors\n"
|
||||||
#define HEALTH_CMDAPI_MSG_ADDED "Alarm selector added\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_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"
|
#define HEALTH_CMDAPI_MSG_NOSELECTORWARNING "WARNING: SILENCE or DISABLE command is ineffective without defining any alarm selectors.\n"
|
||||||
|
|
||||||
|
|
|
@ -664,7 +664,7 @@
|
||||||
{
|
{
|
||||||
"name": "cmd",
|
"name": "cmd",
|
||||||
"in": "query",
|
"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,
|
"required": false,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
@ -672,8 +672,7 @@
|
||||||
"SILENCE ALL",
|
"SILENCE ALL",
|
||||||
"DISABLE",
|
"DISABLE",
|
||||||
"SILENCE",
|
"SILENCE",
|
||||||
"RESET",
|
"RESET"
|
||||||
"LIST"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -437,10 +437,10 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- name: cmd
|
- name: cmd
|
||||||
in: query
|
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
|
required: false
|
||||||
type: string
|
type: string
|
||||||
enum: ['DISABLE ALL', 'SILENCE ALL', 'DISABLE', 'SILENCE', 'RESET', 'LIST']
|
enum: ['DISABLE ALL', 'SILENCE ALL', 'DISABLE', 'SILENCE', 'RESET']
|
||||||
- name: alarm
|
- name: alarm
|
||||||
in: query
|
in: query
|
||||||
description: 'The expression provided will match both `alarm` and `template` names.'
|
description: 'The expression provided will match both `alarm` and `template` names.'
|
||||||
|
|
Loading…
Add table
Reference in a new issue