diff options
Diffstat (limited to 'libnetdata')
31 files changed, 1065 insertions, 2489 deletions
diff --git a/libnetdata/buffer/buffer.h b/libnetdata/buffer/buffer.h index 9f6cab5e8c..25889f807d 100644 --- a/libnetdata/buffer/buffer.h +++ b/libnetdata/buffer/buffer.h @@ -36,37 +36,6 @@ typedef enum __attribute__ ((__packed__)) { } BUFFER_OPTIONS; typedef enum __attribute__ ((__packed__)) { - CT_NONE = 0, - CT_APPLICATION_JSON, - CT_TEXT_PLAIN, - CT_TEXT_HTML, - CT_APPLICATION_X_JAVASCRIPT, - CT_TEXT_CSS, - CT_TEXT_XML, - CT_APPLICATION_XML, - CT_TEXT_XSL, - CT_APPLICATION_OCTET_STREAM, - CT_APPLICATION_X_FONT_TRUETYPE, - CT_APPLICATION_X_FONT_OPENTYPE, - CT_APPLICATION_FONT_WOFF, - CT_APPLICATION_FONT_WOFF2, - CT_APPLICATION_VND_MS_FONTOBJ, - CT_IMAGE_SVG_XML, - CT_IMAGE_PNG, - CT_IMAGE_JPG, - CT_IMAGE_GIF, - CT_IMAGE_XICON, - CT_IMAGE_ICNS, - CT_IMAGE_BMP, - CT_PROMETHEUS, - CT_AUDIO_MPEG, - CT_AUDIO_OGG, - CT_VIDEO_MP4, - CT_APPLICATION_PDF, - CT_APPLICATION_ZIP, -} HTTP_CONTENT_TYPE; - -typedef enum __attribute__ ((__packed__)) { BUFFER_JSON_OPTIONS_DEFAULT = 0, BUFFER_JSON_OPTIONS_MINIFY = (1 << 0), BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS = (1 << 1), @@ -164,6 +133,9 @@ void buffer_json_finalize(BUFFER *wb); static const char *buffer_tostring(BUFFER *wb) { + if(unlikely(!wb)) + return NULL; + buffer_need_bytes(wb, 1); wb->buffer[wb->len] = '\0'; @@ -1249,4 +1221,26 @@ buffer_rrdf_table_add_field(BUFFER *wb, size_t field_id, const char *key, const buffer_json_object_close(wb); } +static inline void buffer_copy(BUFFER *dst, BUFFER *src) { + if(!src || !dst) + return; + + buffer_contents_replace(dst, buffer_tostring(src), buffer_strlen(src)); + + dst->content_type = src->content_type; + dst->options = src->options; + dst->date = src->date; + dst->expires = src->expires; + dst->json = src->json; +} + +static inline BUFFER *buffer_dup(BUFFER *src) { + if(!src) + return NULL; + + BUFFER *dst = buffer_create(buffer_strlen(src) + 1, src->statistics); + buffer_copy(dst, src); + return dst; +} + #endif /* NETDATA_WEB_BUFFER_H */ diff --git a/libnetdata/config/dyncfg.c b/libnetdata/config/dyncfg.c new file mode 100644 index 0000000000..82e20053bd --- /dev/null +++ b/libnetdata/config/dyncfg.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "../libnetdata.h" + +// ---------------------------------------------------------------------------- + +static struct { + DYNCFG_TYPE type; + const char *name; +} dyncfg_types[] = { + { .type = DYNCFG_TYPE_SINGLE, .name = "single" }, + { .type = DYNCFG_TYPE_TEMPLATE, .name = "template" }, + { .type = DYNCFG_TYPE_JOB, .name = "job" }, +}; + +DYNCFG_TYPE dyncfg_type2id(const char *type) { + if(!type || !*type) + return DYNCFG_TYPE_SINGLE; + + size_t entries = sizeof(dyncfg_types) / sizeof(dyncfg_types[0]); + for(size_t i = 0; i < entries ;i++) { + if(strcmp(dyncfg_types[i].name, type) == 0) + return dyncfg_types[i].type; + } + + return DYNCFG_TYPE_SINGLE; +} + +const char *dyncfg_id2type(DYNCFG_TYPE type) { + size_t entries = sizeof(dyncfg_types) / sizeof(dyncfg_types[0]); + for(size_t i = 0; i < entries ;i++) { + if(type == dyncfg_types[i].type) + return dyncfg_types[i].name; + } + + return "single"; +} + +// ---------------------------------------------------------------------------- + +static struct { + DYNCFG_SOURCE_TYPE source_type; + const char *name; +} dyncfg_source_types[] = { + { .source_type = DYNCFG_SOURCE_TYPE_INTERNAL, .name = "internal" }, + { .source_type = DYNCFG_SOURCE_TYPE_STOCK, .name = "stock" }, + { .source_type = DYNCFG_SOURCE_TYPE_USER, .name = "user" }, + { .source_type = DYNCFG_SOURCE_TYPE_DYNCFG, .name = "dyncfg" }, + { .source_type = DYNCFG_SOURCE_TYPE_DISCOVERED, .name = "discovered" }, +}; + +DYNCFG_SOURCE_TYPE dyncfg_source_type2id(const char *source_type) { + if(!source_type || !*source_type) + return DYNCFG_SOURCE_TYPE_INTERNAL; + + size_t entries = sizeof(dyncfg_source_types) / sizeof(dyncfg_source_types[0]); + for(size_t i = 0; i < entries ;i++) { + if(strcmp(dyncfg_source_types[i].name, source_type) == 0) + return dyncfg_source_types[i].source_type; + } + + return DYNCFG_SOURCE_TYPE_INTERNAL; +} + +const char *dyncfg_id2source_type(DYNCFG_SOURCE_TYPE source_type) { + size_t entries = sizeof(dyncfg_source_types) / sizeof(dyncfg_source_types[0]); + for(size_t i = 0; i < entries ;i++) { + if(source_type == dyncfg_source_types[i].source_type) + return dyncfg_source_types[i].name; + } + + return "internal"; +} + +// ---------------------------------------------------------------------------- + +static struct { + DYNCFG_STATUS status; + const char *name; +} dyncfg_statuses[] = { + { .status = DYNCFG_STATUS_NONE, .name = "none" }, + { .status = DYNCFG_STATUS_ACCEPTED, .name = "accepted" }, + { .status = DYNCFG_STATUS_RUNNING, .name = "running" }, + { .status = DYNCFG_STATUS_FAILED, .name = "failed" }, + { .status = DYNCFG_STATUS_DISABLED, .name = "disabled" }, + { .status = DYNCFG_STATUS_ORPHAN, .name = "orphan" }, + { .status = DYNCFG_STATUS_INCOMPLETE, .name = "incomplete" }, +}; + +DYNCFG_STATUS dyncfg_status2id(const char *status) { + if(!status || !*status) + return DYNCFG_STATUS_NONE; + + size_t entries = sizeof(dyncfg_statuses) / sizeof(dyncfg_statuses[0]); + for(size_t i = 0; i < entries ;i++) { + if(strcmp(dyncfg_statuses[i].name, status) == 0) + return dyncfg_statuses[i].status; + } + + return DYNCFG_STATUS_NONE; +} + +const char *dyncfg_id2status(DYNCFG_STATUS status) { + size_t entries = sizeof(dyncfg_statuses) / sizeof(dyncfg_statuses[0]); + for(size_t i = 0; i < entries ;i++) { + if(status == dyncfg_statuses[i].status) + return dyncfg_statuses[i].name; + } + + return "none"; +} + +// ---------------------------------------------------------------------------- + +static struct { + DYNCFG_CMDS cmd; + const char *name; +} cmd_map[] = { + { .cmd = DYNCFG_CMD_GET, .name = "get" }, + { .cmd = DYNCFG_CMD_SCHEMA, .name = "schema" }, + { .cmd = DYNCFG_CMD_UPDATE, .name = "update" }, + { .cmd = DYNCFG_CMD_ADD, .name = "add" }, + { .cmd = DYNCFG_CMD_TEST, .name = "test" }, + { .cmd = DYNCFG_CMD_REMOVE, .name = "remove" }, + { .cmd = DYNCFG_CMD_ENABLE, .name = "enable" }, + { .cmd = DYNCFG_CMD_DISABLE, .name = "disable" }, + { .cmd = DYNCFG_CMD_RESTART, .name = "restart" } +}; + +const char *dyncfg_id2cmd_one(DYNCFG_CMDS cmd) { + for (size_t i = 0; i < sizeof(cmd_map) / sizeof(cmd_map[0]); i++) { + if(cmd == cmd_map[i].cmd) + return cmd_map[i].name; + } + + return NULL; +} + +DYNCFG_CMDS dyncfg_cmds2id(const char *cmds) { + if(!cmds || !*cmds) + return DYNCFG_CMD_NONE; + + DYNCFG_CMDS result = DYNCFG_CMD_NONE; + const char *p = cmds; + size_t len, i; + + while (*p) { + // Skip any leading spaces + while (*p == ' ') p++; + + // Find the end of the current word + const char *end = p; + while (*end && *end != ' ') end++; + len = end - p; + + // Compare with known commands + for (i = 0; i < sizeof(cmd_map) / sizeof(cmd_map[0]); i++) { + if (strncmp(p, cmd_map[i].name, len) == 0 && cmd_map[i].name[len] == '\0') { + result |= cmd_map[i].cmd; + break; + } + } + + // Move to the next word + p = end; + } + + return result; +} + +void dyncfg_cmds2fp(DYNCFG_CMDS cmds, FILE *fp) { + for (size_t i = 0; i < sizeof(cmd_map) / sizeof(cmd_map[0]); i++) { + if(cmds & cmd_map[i].cmd) + fprintf(fp, "%s ", cmd_map[i].name); + } +} + +void dyncfg_cmds2json_array(DYNCFG_CMDS cmds, const char *key, BUFFER *wb) { + buffer_json_member_add_array(wb, key); + for (size_t i = 0; i < sizeof(cmd_map) / sizeof(cmd_map[0]); i++) { + if(cmds & cmd_map[i].cmd) + buffer_json_add_array_item_string(wb, cmd_map[i].name); + } + buffer_json_array_close(wb); +} + +void dyncfg_cmds2buffer(DYNCFG_CMDS cmds, BUFFER *wb) { + size_t added = 0; + for (size_t i = 0; i < sizeof(cmd_map) / sizeof(cmd_map[0]); i++) { + if(cmds & cmd_map[i].cmd) { + if(added) + buffer_fast_strcat(wb, " ", 1); + + buffer_strcat(wb, cmd_map[i].name); + added++; + } + } +} + +// ---------------------------------------------------------------------------- + +bool dyncfg_is_valid_id(const char *id) { + const char *s = id; + + while(*s) { + if(isspace(*s) || *s == '\'') return false; + s++; + } + + return true; +} + +char *dyncfg_escape_id_for_filename(const char *id) { + if (id == NULL) return NULL; + + // Allocate memory for the worst case, where every character is escaped. + char *escaped = mallocz(strlen(id) * 3 + 1); // Each char can become '%XX', plus '\0' + if (!escaped) return NULL; + + const char *src = id; + char *dest = escaped; + + while (*src) { + if (*src == '/' || isspace(*src) || !isprint(*src)) { + sprintf(dest, "%%%02X", (unsigned char)*src); + dest += 3; + } else { + *dest++ = *src; + } + src++; + } + + *dest = '\0'; + return escaped; +} + +// ---------------------------------------------------------------------------- + +int dyncfg_default_response(BUFFER *wb, int code, const char *msg) { + buffer_flush(wb); + wb->content_type = CT_APPLICATION_JSON; + wb->expires = now_realtime_sec(); + + buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY); + buffer_json_member_add_uint64(wb, "status", code); + buffer_json_member_add_string(wb, "message", msg); + buffer_json_finalize(wb); + + return code; +} + +int dyncfg_node_find_and_call(DICTIONARY *dyncfg_nodes, const char *transaction, const char *function, + usec_t *stop_monotonic_ut, bool *cancelled, + BUFFER *payload, const char *source, BUFFER *result) { + if(!function || !*function) + return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "command received is empty"); + + char buf[strlen(function) + 1]; + memcpy(buf, function, sizeof(buf)); + + char *words[MAX_FUNCTION_PARAMETERS]; // an array of pointers for the words in this line + size_t num_words = quoted_strings_splitter_pluginsd(buf, words, MAX_FUNCTION_PARAMETERS); + + const char *id = get_word(words, num_words, 1); + const char *action = get_word(words, num_words, 2); + + if(!id || !*id) + return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "dyncfg node: id is missing from the request"); + + if(!action || !*action) + return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "dyncfg node: action is missing from the request"); + + DYNCFG_CMDS cmd = dyncfg_cmds2id(action); + if(cmd == DYNCFG_CMD_NONE) + return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "dyncfg node: action given in request is unknown"); + + const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(dyncfg_nodes, id); + if(!item) + return dyncfg_default_response(result, HTTP_RESP_NOT_FOUND, "dyncfg node: id is not found"); + + struct dyncfg_node *df = dictionary_acquired_item_value(item); + + buffer_flush(result); + result->content_type = CT_APPLICATION_JSON; + + int code = df->cb(transaction, id, cmd, payload, stop_monotonic_ut, cancelled, result, source, df->data); + + if(!result->expires) + result->expires = now_realtime_sec(); + + if(!buffer_tostring(result)) + dyncfg_default_response(result, code, ""); + + dictionary_acquired_item_release(dyncfg_nodes, item); + + return code; +} diff --git a/libnetdata/config/dyncfg.h b/libnetdata/config/dyncfg.h new file mode 100644 index 0000000000..35214ba19e --- /dev/null +++ b/libnetdata/config/dyncfg.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef LIBNETDATA_DYNCFG_H +#define LIBNETDATA_DYNCFG_H + +#define DYNCFG_VERSION (size_t)1 + +#define DYNCFG_RESP_SUCCESS(code) (code >= 200 && code <= 299) +#define DYNCFG_RESP_RUNNING 200 // accepted and running +#define DYNCFG_RESP_ACCEPTED 202 // accepted, but not running yet +#define DYNCFG_RESP_ACCEPTED_RESTART_REQUIRED 299 // accepted, but restart is required to apply it + +typedef enum __attribute__((packed)) { + DYNCFG_TYPE_SINGLE = 0, + DYNCFG_TYPE_TEMPLATE, + DYNCFG_TYPE_JOB, +} DYNCFG_TYPE; +DYNCFG_TYPE dyncfg_type2id(const char *type); +const char *dyncfg_id2type(DYNCFG_TYPE type); + +typedef enum __attribute__((packed)) { + DYNCFG_SOURCE_TYPE_INTERNAL = 0, + DYNCFG_SOURCE_TYPE_STOCK, + DYNCFG_SOURCE_TYPE_USER, + DYNCFG_SOURCE_TYPE_DYNCFG, + DYNCFG_SOURCE_TYPE_DISCOVERED, +} DYNCFG_SOURCE_TYPE; +DYNCFG_SOURCE_TYPE dyncfg_source_type2id(const char *source_type); +const char *dyncfg_id2source_type(DYNCFG_SOURCE_TYPE source_type); + +typedef enum __attribute__((packed)) { + DYNCFG_STATUS_NONE = 0, + DYNCFG_STATUS_ACCEPTED, // the plugin has accepted the configuration + DYNCFG_STATUS_RUNNING, // the plugin runs the accepted configuration + DYNCFG_STATUS_FAILED, // the plugin fails to run the accepted configuration + DYNCFG_STATUS_DISABLED, // the configuration is disabled by a user + DYNCFG_STATUS_ORPHAN, // no plugin has claimed this configurations + DYNCFG_STATUS_INCOMPLETE, // a special kind of failed configuration +} DYNCFG_STATUS; +DYNCFG_STATUS dyncfg_status2id(const char *status); +const char *dyncfg_id2status(DYNCFG_STATUS status); + +typedef enum __attribute__((packed)) { + DYNCFG_CMD_NONE = 0, + DYNCFG_CMD_GET = (1 << 0), + DYNCFG_CMD_SCHEMA = (1 << 1), + DYNCFG_CMD_UPDATE = (1 << 2), + DYNCFG_CMD_ADD = (1 << 3), + DYNCFG_CMD_TEST = (1 << 4), + DYNCFG_CMD_REMOVE = (1 << 5), + DYNCFG_CMD_ENABLE = (1 << 6), + DYNCFG_CMD_DISABLE = (1 << 7), + DYNCFG_CMD_RESTART = (1 << 8), +} DYNCFG_CMDS; +DYNCFG_CMDS dyncfg_cmds2id(const char *cmds); +void dyncfg_cmds2buffer(DYNCFG_CMDS cmds, struct web_buffer *wb); +void dyncfg_cmds2json_array(DYNCFG_CMDS cmds, const char *key, struct web_buffer *wb); +void dyncfg_cmds2fp(DYNCFG_CMDS cmds, FILE *fp); +const char *dyncfg_id2cmd_one(DYNCFG_CMDS cmd); + +bool dyncfg_is_valid_id(const char *id); +char *dyncfg_escape_id_for_filename(const char *id); + +#include "../clocks/clocks.h" +#include "../buffer/buffer.h" +#include "../dictionary/dictionary.h" + +typedef int (*dyncfg_cb_t)(const char *transaction, const char *id, DYNCFG_CMDS cmd, BUFFER *payload, usec_t *stop_monotonic_ut, bool *cancelled, BUFFER *result, const char *source, void *data); + +struct dyncfg_node { + DYNCFG_TYPE type; + DYNCFG_CMDS cmds; + dyncfg_cb_t cb; + void *data; +}; + +#define dyncfg_nodes_dictionary_create() dictionary_create_advanced(DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct dyncfg_node)) + +int dyncfg_default_response(BUFFER *wb, int code, const char *msg); + +int dyncfg_node_find_and_call(DICTIONARY *dyncfg_nodes, const char *transaction, const char *function, + usec_t *stop_monotonic_ut, bool *cancelled, + BUFFER *payload, const char *source, BUFFER *result); + +#endif //LIBNETDATA_DYNCFG_H diff --git a/libnetdata/dictionary/dictionary.c b/libnetdata/dictionary/dictionary.c index 4b8fdb95db..0f5c3027a1 100644 --- a/libnetdata/dictionary/dictionary.c +++ b/libnetdata/dictionary/dictionary.c @@ -996,7 +996,9 @@ static int item_check_and_acquire_advanced(DICTIONARY *dict, DICTIONARY_ITEM *it if (having_index_lock) { // delete it from the hashtable if(hashtable_delete_unsafe(dict, item_get_name(item), item->key_len, item) == 0) - netdata_log_error("DICTIONARY: INTERNAL ERROR VIEW: tried to delete item with name '%s', name_len %u that is not in the index", item_get_name(item), (KEY_LEN_TYPE)(item->key_len - 1)); + netdata_log_error("DICTIONARY: INTERNAL ERROR VIEW: tried to delete item with name '%s', " + "name_len %u that is not in the index", + item_get_name(item), (KEY_LEN_TYPE)(item->key_len)); else pointer_del(dict, item); @@ -1237,7 +1239,7 @@ static inline size_t item_set_name(DICTIONARY *dict, DICTIONARY_ITEM *item, cons } else { item->string_name = string_strdupz(name); - item->key_len = string_strlen(item->string_name) + 1; + item->key_len = string_strlen(item->string_name); item->options |= ITEM_OPTION_ALLOCATED_NAME; } @@ -1584,7 +1586,7 @@ static inline void dict_item_release_and_check_if_it_is_deleted_and_can_be_remov static bool dict_item_del(DICTIONARY *dict, const char *name, ssize_t name_len) { if(name_len == -1) - name_len = (ssize_t)strlen(name) + 1; // we need the terminating null too + name_len = (ssize_t)strlen(name); netdata_log_debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name); @@ -1602,9 +1604,9 @@ static bool dict_item_del(DICTIONARY *dict, const char *name, ssize_t name_len) } else { if(hashtable_delete_unsafe(dict, name, name_len, item) == 0) - netdata_log_error("DICTIONARY: INTERNAL ERROR: tried to delete item with name '%s', name_len %zd that is not in the index", - name, - name_len - 1); + netdata_log_error("DICTIONARY: INTERNAL ERROR: tried to delete item with name '%s', " + "name_len %zd that is not in the index", + name, name_len); else pointer_del(dict, item); @@ -1635,7 +1637,7 @@ static DICTIONARY_ITEM *dict_item_add_or_reset_value_and_acquire(DICTIONARY *dic } if(name_len == -1) - name_len = (ssize_t)strlen(name) + 1; // we need the terminating null too + name_len = (ssize_t)strlen(name); netdata_log_debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name); @@ -1754,7 +1756,7 @@ static DICTIONARY_ITEM *dict_item_find_and_acquire(DICTIONARY *dict, const char } if(name_len == -1) - name_len = (ssize_t)strlen(name) + 1; // we need the terminating null too + name_len = (ssize_t)strlen(name); netdata_log_debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name); @@ -1990,11 +1992,12 @@ static bool api_is_name_good_with_trace(DICTIONARY *dict __maybe_unused, const c } internal_error( - name_len > 0 && name_len != (ssize_t)(strlen(name) + 1), - "DICTIONARY: attempted to %s() with a name of '%s', having length of %zu (incl. '\\0'), but the supplied name_len = %ld, on a dictionary created from %s() %zu@%s.", + name_len > 0 && name_len != (ssize_t)strlen(name), + "DICTIONARY: attempted to %s() with a name of '%s', having length of %zu, " + "but the supplied name_len = %ld, on a dictionary created from %s() %zu@%s.", function, name, - strlen(name) + 1, + strlen(name), (long int) name_len, dict?dict->creation_function:"unknown", dict?dict->creation_line:0, @@ -2002,10 +2005,11 @@ static bool api_is_name_good_with_trace(DICTIONARY *dict __maybe_unused, const c internal_error( name_len <= 0 && name_len != -1, - "DICTIONARY: attempted to %s() with a name of '%s', having length of %zu (incl. '\\0'), but the supplied name_len = %ld, on a dictionary created from %s() %zu@%s.", + "DICTIONARY: attempted to %s() with a name of '%s', having length of %zu, " + "but the supplied name_len = %ld, on a dictionary created from %s() %zu@%s.", function, name, - strlen(name) + 1, + strlen(name), (long int) name_len, dict?dict->creation_function:"unknown", dict?dict->creation_line:0, @@ -2109,7 +2113,7 @@ void dictionary_flush(DICTIONARY *dict) { DICTIONARY_ITEM *item, *next = NULL; for(item = dict->items.list; item ;item = next) { next = item->next; - dict_item_del(dict, item_get_name(item), (ssize_t) item_get_name_len(item) + 1); + dict_item_del(dict, item_get_name(item), (ssize_t)item_get_name_len(item)); } ll_recursive_unlock(dict, DICTIONARY_LOCK_WRITE); @@ -2580,7 +2584,7 @@ void *thread_cache_entry_get_or_set(void *key, if(unlikely(!key || !key_length)) return NULL; if(key_length == -1) - key_length = (ssize_t)strlen((char *)key) + 1; + key_length = (ssize_t)strlen((char *)key); JError_t J_Error; Pvoid_t *Rc = JudyHSIns(&thread_cache_judy_array, key, key_length, &J_Error); @@ -2627,7 +2631,7 @@ static char **dictionary_unittest_generate_names(size_t entries) { char **names = mallocz(sizeof(char *) * entries); for(size_t i = 0; i < entries ;i++) { char buf[25 + 1] = ""; - snprintfz(buf, sizeof(buf) - 1, "name.%zu.0123456789.%zu!@#$%%^&*(),./[]{}\\|~`", i, entries / 2 + i); + snprintfz(buf, sizeof(buf), "name.%zu.0123456789.%zu!@#$%%^&*(),./[]{}\\|~`", i, entries / 2 + i); names[i] = strdupz(buf); } return names; @@ -2637,7 +2641,7 @@ static char **dictionary_unittest_generate_values(size_t entries) { char **values = mallocz(sizeof(char *) * entries); for(size_t i = 0; i < entries ;i++) { char buf[25 + 1] = ""; - snprintfz(buf, sizeof(buf) - 1, "value-%zu-0987654321.%zu%%^&*(),. \t !@#$/[]{}\\|~`", i, entries / 2 + i); + snprintfz(buf, sizeof(buf), "value-%zu-0987654321.%zu%%^&*(),. \t !@#$/[]{}\\|~`", i, entries / 2 + i); values[i] = strdupz(buf); } return values; @@ -2646,7 +2650,7 @@ static char **dictionary_unittest_generate_values(size_t entries) { static size_t dictionary_unittest_set_clone(DICTIONARY *dict, char **names, char **values, size_t entries) { size_t errors = 0; for(size_t i = 0; i < entries ;i++) { - size_t vallen = strlen(values[i]) + 1; + size_t vallen = strlen(values[i]); char *val = (char *)dictionary_set(dict, names[i], values[i], vallen); if(val == values[i]) { fprintf(stderr, ">>> %s() returns reference to value\n", __FUNCTION__); errors++; } if(!val || memcmp(val, values[i], vallen) != 0) { fprintf(stderr, ">>> %s() returns invalid value\n", __FUNCTION__); errors++; } @@ -2673,7 +2677,7 @@ static size_t dictionary_unittest_set_null(DICTIONARY *dict, char **names, char static size_t dictionary_unittest_set_nonclone(DICTIONARY *dict, char **names, char **values, size_t entries) { size_t errors = 0; for(size_t i = 0; i < entries ;i++) { - size_t vallen = strlen(values[i]) + 1; + size_t vallen = strlen(values[i]); char *val = (char *)dictionary_set(dict, names[i], values[i], vallen); if(val != values[i]) { fprintf(stderr, ">>> %s() returns invalid pointer to value\n", __FUNCTION__); errors++; } } @@ -2683,7 +2687,7 @@ static size_t dictionary_unittest_set_nonclone(DICTIONARY *dict, char **names, c static size_t dictionary_unittest_get_clone(DICTIONARY *dict, char **names, char **values, size_t entries) { size_t errors = 0; for(size_t i = 0; i < entries ;i++) { - size_t vallen = strlen(values[i]) + 1; + size_t vallen = strlen(values[i]); char *val = (char *)dictionary_get(dict, names[i]); if(val == values[i]) { fprintf(stderr, ">>> %s() returns reference to value\n", __FUNCTION__); errors++; } if(!val || memcmp(val, values[i], vallen) != 0) { fprintf(stderr, ">>> %s() returns invalid value\n", __FUNCTION__); errors++; } @@ -2751,7 +2755,7 @@ static size_t dictionary_unittest_reset_clone(DICTIONARY *dict, char **names, ch // set the name as value too size_t errors = 0; for(size_t i = 0; i < entries ;i++) { - size_t vallen = strlen(names[i]) + 1; + size_t vallen = strlen(names[i]); char *val = (char *)dictionary_set(dict, names[i], names[i], vallen); if(val == names[i]) { fprintf(stderr, ">>> %s() returns reference to value\n", __FUNCTION__); errors++; } if(!val || memcmp(val, names[i], vallen) != 0) { fprintf(stderr, ">>> %s() returns invalid value\n", __FUNCTION__); errors++; } @@ -2764,7 +2768,7 @@ static size_t dictionary_unittest_reset_nonclone(DICTIONARY *dict, char **names, // set the name as value too size_t errors = 0; for(size_t i = 0; i < entries ;i++) { - size_t vallen = strlen(names[i]) + 1; + size_t vallen = strlen(names[i]); char *val = (char *)dictionary_set(dict, names[i], names[i], vallen); if(val != names[i]) { fprintf(stderr, ">>> %s() returns invalid pointer to value\n", __FUNCTION__); errors++; } if(!val) { fprintf(stderr, ">>> %s() returns invalid value\n", __FUNCTION__); errors++; } @@ -2776,7 +2780,7 @@ static size_t dictionary_unittest_reset_dont_overwrite_nonclone(DICTIONARY *dict // set the name as value too size_t errors = 0; for(size_t i = 0; i < entries ;i++) { - size_t vallen = strlen(names[i]) + 1; + size_t vallen = strlen(names[i]); char *val = (char *)dictionary_set(dict, names[i], names[i], vallen); if(val != values[i]) { fprintf(stderr, ">>> %s() returns invalid pointer to value\n", __FUNCTION__); errors++; } } @@ -3253,13 +3257,13 @@ static void *unittest_dict_thread(void *arg) { char buf [256 + 1]; for (int i = 0; i < 1000; i++) { - snprintfz(buf, sizeof(buf) - 1, "del/flush test %d", i); + snprintfz(buf, sizeof(buf), "del/flush test %d", i); dictionary_set(tu->dict, buf, NULL, 0); tu->stats.ops.inserts++; } for (int i = 0; i < 1000; i++) { - snprintfz(buf, sizeof(buf) - 1, "del/flush test %d", i); + snprintfz(buf, sizeof(buf), "del/flush test %d", i); dictionary_del(tu->dict, buf); tu->stats.ops.deletes++; } @@ -3392,7 +3396,7 @@ static void *unittest_dict_master_thread(void *arg) { while(!__atomic_load_n(&tv->join, __ATOMIC_RELAXED)) { if(!item) - item = dictionary_set_and_acquire_item(tv->master, "ITEM1", "123", strlen("123") + 1); + item = dictionary_set_and_acquire_item(tv->master, "ITEM1", "123", strlen("123")); if(__atomic_load_n(&tv->item_master, __ATOMIC_RELAXED) != NULL) { dictionary_acquired_item_release(tv->master, item); diff --git a/libnetdata/dyn_conf/README.md b/libnetdata/dyn_conf/README.md deleted file mode 100644 index 17d059b024..0000000000 --- a/libnetdata/dyn_conf/README.md +++ /dev/null @@ -1,188 +0,0 @@ -# Netdata Dynamic Configuration - -Purpose of Netdata Dynamic Configuration is to allow configuration of select Netdata plugins and options through the -Netdata API and by extension by UI. - -## HTTP API documentation - -### Summary API - -For summary of all jobs and their statuses (for all children that stream to parent) use the following URL: - -| Method | Endpoint | Description | -|:-------:|-------------------------------|------------------------------------------------------------| -| **GET** | `api/v2/job_statuses` | list of Jobs | -| **GET** | `api/v2/job_statuses?grouped` | list of Jobs (hierarchical, grouped by host/plugin/module) | |