summaryrefslogtreecommitdiffstats
path: root/web/api/web_api_v1.c
diff options
context:
space:
mode:
Diffstat (limited to 'web/api/web_api_v1.c')
-rw-r--r--web/api/web_api_v1.c764
1 files changed, 279 insertions, 485 deletions
diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c
index 1b38a33b..6e23549d 100644
--- a/web/api/web_api_v1.c
+++ b/web/api/web_api_v1.c
@@ -41,7 +41,12 @@ static struct {
, {"natural-points" , 0 , RRDR_OPTION_NATURAL_POINTS}
, {"virtual-points" , 0 , RRDR_OPTION_VIRTUAL_POINTS}
, {"all-dimensions" , 0 , RRDR_OPTION_ALL_DIMENSIONS}
- , {"plan" , 0 , RRDR_OPTION_SHOW_PLAN}
+ , {"details" , 0 , RRDR_OPTION_SHOW_DETAILS}
+ , {"debug" , 0 , RRDR_OPTION_DEBUG}
+ , {"plan" , 0 , RRDR_OPTION_DEBUG}
+ , {"minify" , 0 , RRDR_OPTION_MINIFY}
+ , {"group-by-labels" , 0 , RRDR_OPTION_GROUP_BY_LABELS}
+ , {"label-quotes" , 0 , RRDR_OPTION_LABEL_QUOTES}
, {NULL , 0 , 0}
};
@@ -53,6 +58,7 @@ static struct {
{ DATASOURCE_FORMAT_DATATABLE_JSON , 0 , DATASOURCE_DATATABLE_JSON}
, {DATASOURCE_FORMAT_DATATABLE_JSONP, 0 , DATASOURCE_DATATABLE_JSONP}
, {DATASOURCE_FORMAT_JSON , 0 , DATASOURCE_JSON}
+ , {DATASOURCE_FORMAT_JSON2 , 0 , DATASOURCE_JSON2}
, {DATASOURCE_FORMAT_JSONP , 0 , DATASOURCE_JSONP}
, {DATASOURCE_FORMAT_SSV , 0 , DATASOURCE_SSV}
, {DATASOURCE_FORMAT_CSV , 0 , DATASOURCE_CSV}
@@ -63,7 +69,9 @@ static struct {
, {DATASOURCE_FORMAT_SSV_COMMA , 0 , DATASOURCE_SSV_COMMA}
, {DATASOURCE_FORMAT_CSV_JSON_ARRAY , 0 , DATASOURCE_CSV_JSON_ARRAY}
, {DATASOURCE_FORMAT_CSV_MARKDOWN , 0 , DATASOURCE_CSV_MARKDOWN}
- , { NULL, 0, 0}
+
+ // terminator
+ , {NULL, 0, 0}
};
static struct {
@@ -92,7 +100,7 @@ void web_client_api_v1_init(void) {
for(i = 0; api_v1_data_google_formats[i].name ; i++)
api_v1_data_google_formats[i].hash = simple_hash(api_v1_data_google_formats[i].name);
- web_client_api_v1_init_grouping();
+ time_grouping_init();
uuid_t uuid;
@@ -170,7 +178,7 @@ inline RRDR_OPTIONS web_client_api_request_v1_data_options(char *o) {
RRDR_OPTIONS ret = 0x00000000;
char *tok;
- while(o && *o && (tok = mystrsep(&o, ", |"))) {
+ while(o && *o && (tok = strsep_skip_consecutive_separators(&o, ", |"))) {
if(!*tok) continue;
uint32_t hash = simple_hash(tok);
@@ -186,20 +194,20 @@ inline RRDR_OPTIONS web_client_api_request_v1_data_options(char *o) {
return ret;
}
-void web_client_api_request_v1_data_options_to_buffer(BUFFER *wb, RRDR_OPTIONS options) {
+void web_client_api_request_v1_data_options_to_buffer_json_array(BUFFER *wb, const char *key, RRDR_OPTIONS options) {
+ buffer_json_member_add_array(wb, key);
+
RRDR_OPTIONS used = 0; // to prevent adding duplicates
- int added = 0;
for(int i = 0; api_v1_data_options[i].name ; i++) {
if (unlikely((api_v1_data_options[i].value & options) && !(api_v1_data_options[i].value & used))) {
const char *name = api_v1_data_options[i].name;
used |= api_v1_data_options[i].value;
- if(added) buffer_strcat(wb, ",");
- buffer_strcat(wb, name);
-
- added++;
+ buffer_json_add_array_item_string(wb, name);
}
}
+
+ buffer_json_array_close(wb);
}
void web_client_api_request_v1_data_options_to_string(char *buf, size_t size, RRDR_OPTIONS options) {
@@ -254,11 +262,11 @@ inline uint32_t web_client_api_request_v1_data_google_format(char *name) {
int web_client_api_request_v1_alarms_select (char *url) {
int all = 0;
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if (!value || !*value) continue;
- if(!strcmp(value, "all")) all = 1;
- else if(!strcmp(value, "active")) all = 0;
+ if(!strcmp(value, "all") || !strcmp(value, "all=true")) all = 1;
+ else if(!strcmp(value, "active") || !strcmp(value, "active=true")) all = 0;
}
return all;
@@ -268,7 +276,7 @@ inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w,
int all = web_client_api_request_v1_alarms_select(url);
buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
health_alarms2json(host, w->response.data, all);
buffer_no_cacheable(w->response.data);
return HTTP_RESP_OK;
@@ -278,7 +286,7 @@ inline int web_client_api_request_v1_alarms_values(RRDHOST *host, struct web_cli
int all = web_client_api_request_v1_alarms_select(url);
buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
health_alarms_values2json(host, w->response.data, all);
buffer_no_cacheable(w->response.data);
return HTTP_RESP_OK;
@@ -292,10 +300,10 @@ inline int web_client_api_request_v1_alarm_count(RRDHOST *host, struct web_clien
buffer_sprintf(w->response.data, "[");
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if(!value || !*value) continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if(!name || !*name) continue;
if(!value || !*value) continue;
@@ -321,7 +329,7 @@ inline int web_client_api_request_v1_alarm_count(RRDHOST *host, struct web_clien
health_aggregate_alarms(host, w->response.data, contexts, status);
buffer_sprintf(w->response.data, "]\n");
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
buffer_no_cacheable(w->response.data);
buffer_free(contexts);
@@ -333,10 +341,10 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client
char *chart = NULL;
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if (!value || !*value) continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if(!name || !*name) continue;
if(!value || !*value) continue;
@@ -345,7 +353,7 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client
}
buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
health_alarm_log2json(host, w->response.data, after, chart);
return HTTP_RESP_OK;
}
@@ -357,10 +365,10 @@ inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client
buffer_flush(w->response.data);
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if(!value || !*value) continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if(!name || !*name) continue;
if(!value || !*value) continue;
@@ -388,7 +396,7 @@ inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client
goto cleanup;
}
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
st->last_accessed_time_s = now_realtime_sec();
callback(st, w->response.data);
return HTTP_RESP_OK;
@@ -401,38 +409,6 @@ inline int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_c
return web_client_api_request_single_chart(host, w, url, health_api_v1_chart_variables2json);
}
-static RRDCONTEXT_TO_JSON_OPTIONS rrdcontext_to_json_parse_options(char *o) {
- RRDCONTEXT_TO_JSON_OPTIONS options = RRDCONTEXT_OPTION_NONE;
- char *tok;
-
- while(o && *o && (tok = mystrsep(&o, ", |"))) {
- if(!*tok) continue;
-
- if(!strcmp(tok, "full") || !strcmp(tok, "all"))
- options |= RRDCONTEXT_OPTIONS_ALL;
- else if(!strcmp(tok, "charts") || !strcmp(tok, "instances"))
- options |= RRDCONTEXT_OPTION_SHOW_INSTANCES;
- else if(!strcmp(tok, "dimensions") || !strcmp(tok, "metrics"))
- options |= RRDCONTEXT_OPTION_SHOW_METRICS;
- else if(!strcmp(tok, "queue"))
- options |= RRDCONTEXT_OPTION_SHOW_QUEUED;
- else if(!strcmp(tok, "flags"))
- options |= RRDCONTEXT_OPTION_SHOW_FLAGS;
- else if(!strcmp(tok, "uuids"))
- options |= RRDCONTEXT_OPTION_SHOW_UUIDS;
- else if(!strcmp(tok, "deleted"))
- options |= RRDCONTEXT_OPTION_SHOW_DELETED;
- else if(!strcmp(tok, "labels"))
- options |= RRDCONTEXT_OPTION_SHOW_LABELS;
- else if(!strcmp(tok, "deepscan"))
- options |= RRDCONTEXT_OPTION_DEEPSCAN;
- else if(!strcmp(tok, "hidden"))
- options |= RRDCONTEXT_OPTION_SHOW_HIDDEN;
- }
-
- return options;
-}
-
static int web_client_api_request_v1_context(RRDHOST *host, struct web_client *w, char *url) {
char *context = NULL;
RRDCONTEXT_TO_JSON_OPTIONS options = RRDCONTEXT_OPTION_NONE;
@@ -443,10 +419,10 @@ static int web_client_api_request_v1_context(RRDHOST *host, struct web_client *w
buffer_flush(w->response.data);
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if(!value || !*value) continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if(!name || !*name) continue;
if(!value || !*value) continue;
@@ -476,17 +452,19 @@ static int web_client_api_request_v1_context(RRDHOST *host, struct web_client *w
SIMPLE_PATTERN *chart_dimensions_pattern = NULL;
if(chart_label_key)
- chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT, true);
if(chart_labels_filter)
- chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT,
+ true);
if(dimensions) {
- chart_dimensions_pattern = simple_pattern_create(buffer_tostring(dimensions), ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ chart_dimensions_pattern = simple_pattern_create(buffer_tostring(dimensions), ",|\t\r\n\f\v",
+ SIMPLE_PATTERN_EXACT, true);
buffer_free(dimensions);
}
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
int ret = rrdcontext_to_json(host, w->response.data, after, before, options, context, chart_label_key_pattern, chart_labels_filter_pattern, chart_dimensions_pattern);
simple_pattern_free(chart_label_key_pattern);
@@ -505,10 +483,10 @@ static int web_client_api_request_v1_contexts(RRDHOST *host, struct web_client *
buffer_flush(w->response.data);
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if(!value || !*value) continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if(!name || !*name) continue;
if(!value || !*value) continue;
@@ -532,17 +510,19 @@ static int web_client_api_request_v1_contexts(RRDHOST *host, struct web_client *
SIMPLE_PATTERN *chart_dimensions_pattern = NULL;
if(chart_label_key)
- chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT, true);
if(chart_labels_filter)
- chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT,
+ true);
if(dimensions) {
- chart_dimensions_pattern = simple_pattern_create(buffer_tostring(dimensions), ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
+ chart_dimensions_pattern = simple_pattern_create(buffer_tostring(dimensions), ",|\t\r\n\f\v",
+ SIMPLE_PATTERN_EXACT, true);
buffer_free(dimensions);
}
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
int ret = rrdcontexts_to_json(host, w->response.data, after, before, options, chart_label_key_pattern, chart_labels_filter_pattern, chart_dimensions_pattern);
simple_pattern_free(chart_label_key_pattern);
@@ -556,7 +536,7 @@ inline int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w,
(void)url;
buffer_flush(w->response.data);
- w->response.data->contenttype = CT_APPLICATION_JSON;
+ w->response.data->content_type = CT_APPLICATION_JSON;
charts2json(host, w->response.data, 0, 0);
return HTTP_RESP_OK;
}
@@ -565,18 +545,8 @@ inline int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w,
return web_client_api_request_single_chart(host, w, url, rrd_stats_api_v1_chart);
}
-void fix_google_param(char *s) {
- if(unlikely(!s)) return;
-
- for( ; *s ;s++) {
- if(!isalnum(*s) && *s != '.' && *s != '_' && *s != '-')
- *s = '_';
- }
-}
-
-
// returns the HTTP code
-inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
+static inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, char *url) {
debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
int ret = HTTP_RESP_BAD_REQUEST;
@@ -604,15 +574,15 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
char *chart_labels_filter = NULL;
char *group_options = NULL;
size_t tier = 0;
- RRDR_GROUPING group = RRDR_GROUPING_AVERAGE;
+ RRDR_TIME_GROUPING group = RRDR_GROUPING_AVERAGE;
DATASOURCE_FORMAT format = DATASOURCE_JSON;
RRDR_OPTIONS options = 0;
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if(!value || !*value) continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if(!name || !*name) continue;
if(!value || !*value) continue;
@@ -638,7 +608,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
else if(!strcmp(name, "gtime")) group_time_str = value;
else if(!strcmp(name, "group_options")) group_options = value;
else if(!strcmp(name, "group")) {
- group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
+ group = time_grouping_parse(value, RRDR_GROUPING_AVERAGE);
}
else if(!strcmp(name, "format")) {
format = web_client_api_request_v1_data_format(value);
@@ -658,10 +628,10 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
char *tqx_name, *tqx_value;
while(value) {
- tqx_value = mystrsep(&value, ";");
+ tqx_value = strsep_skip_consecutive_separators(&value, ";");
if(!tqx_value || !*tqx_value) continue;
- tqx_name = mystrsep(&tqx_value, ":");
+ tqx_name = strsep_skip_consecutive_separators(&tqx_value, ":");
if(!tqx_name || !*tqx_name) continue;
if(!tqx_value || !*tqx_value) continue;
@@ -722,26 +692,29 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
long group_time = (group_time_str && *group_time_str)?str2l(group_time_str):0;
QUERY_TARGET_REQUEST qtr = {
+ .version = 1,
.after = after,
.before = before,
.host = host,
.st = st,
- .hosts = NULL,
+ .nodes = NULL,
.contexts = context,
- .charts = chart,
+ .instances = chart,
.dimensions = (dimensions)?buffer_tostring(dimensions):NULL,
- .timeout = timeout,
+ .timeout_ms = timeout,
.points = points,
.format = format,
.options = options,
- .group_method = group,
- .group_options = group_options,
+ .time_group_method = group,
+ .time_group_options = group_options,
.resampling_time = group_time,
.tier = tier,
.chart_label_key = chart_label_key,
- .charts_labels_filter = chart_labels_filter,
+ .labels = chart_labels_filter,
.query_source = QUERY_SOURCE_API_DATA,
.priority = STORAGE_PRIORITY_NORMAL,
+ .interrupt_callback = web_client_interrupt_callback,
+ .interrupt_callback_data = w,
};
qt = query_target_create(&qtr);
@@ -751,22 +724,12 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
goto cleanup;
}
- if (timeout) {
- struct timeval now;
- now_realtime_timeval(&now);
- int inqueue = (int)dt_usec(&w->tv_in, &now) / 1000;
- timeout -= inqueue;
- if (timeout <= 0) {
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Query timeout exceeded");
- ret = HTTP_RESP_BACKEND_FETCH_FAILED;
- goto cleanup;
- }
+ web_client_timeout_checkpoint_set(w, timeout);
+ if(web_client_timeout_checkpoint_and_check(w, NULL)) {
+ ret = w->response.code;
+ goto cleanup;
}
- debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%u', format '%u', options '0x%08x'"
- , w->id, chart, (dimensions)?buffer_tostring(dimensions):"", after, before , points, group, format, options);
-
if(outFileName && *outFileName) {
buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
@@ -814,10 +777,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
buffer_strcat(w->response.data, ");");
cleanup:
- if(qt && qt->used) {
- internal_error(true, "QUERY_TARGET: left non-released on query '%s'", qt->id);
- query_target_release(qt);
- }
+ query_target_release(qt);
onewayalloc_destroy(owa);
buffer_free(dimensions);
return ret;
@@ -886,10 +846,10 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
buffer_no_cacheable(w->response.data);
while(url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if (!value || !*value) continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if (!name || !*name) continue;
if (!value || !*value) continue;
@@ -1013,8 +973,10 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
}
}
-static inline void web_client_api_request_v1_info_summary_alarm_statuses(RRDHOST *host, BUFFER *wb) {
- int alarm_normal = 0, alarm_warn = 0, alarm_crit = 0;
+void web_client_api_request_v1_info_summary_alarm_statuses(RRDHOST *host, BUFFER *wb, const char *key) {
+ buffer_json_member_add_object(wb, key);
+
+ size_t normal = 0, warning = 0, critical = 0;
RRDCALC *rc;
foreach_rrdcalc_in_rrdhost_read(host, rc) {
if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
@@ -1022,274 +984,217 @@ static inline void web_client_api_request_v1_info_summary_alarm_statuses(RRDHOST
switch(rc->status) {
case RRDCALC_STATUS_WARNING:
- alarm_warn++;
+ warning++;
break;
case RRDCALC_STATUS_CRITICAL:
- alarm_crit++;
+ critical++;
break;
default:
- alarm_normal++;
+ normal++;
}
}
foreach_rrdcalc_in_rrdhost_done(rc);
- buffer_sprintf(wb, "\t\t\"normal\": %d,\n", alarm_normal);
- buffer_sprintf(wb, "\t\t\"warning\": %d,\n", alarm_warn);
- buffer_sprintf(wb, "\t\t\"critical\": %d\n", alarm_crit);
+
+ buffer_json_member_add_uint64(wb, "normal", normal);
+ buffer_json_member_add_uint64(wb, "warning", warning);
+ buffer_json_member_add_uint64(wb, "critical", critical);
+
+ buffer_json_object_close(wb);
+}
+
+static inline void web_client_api_request_v1_info_mirrored_hosts_status(BUFFER *wb, RRDHOST *host) {
+ buffer_json_add_array_item_object(wb);
+
+ buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(host));
+ buffer_json_member_add_uint64(wb, "hops", host->system_info ? host->system_info->hops : (host == localhost) ? 0 : 1);
+ buffer_json_member_add_boolean(wb, "reachable", (host == localhost || !rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN)));
+
+ buffer_json_member_add_string(wb, "guid", host->machine_guid);
+ buffer_json_member_add_uuid(wb, "node_id", host->node_id);
+ rrdhost_aclk_state_lock(host);
+ buffer_json_member_add_string(wb, "claim_id", host->aclk_state.claimed_id);
+ rrdhost_aclk_state_unlock(host);
+
+ buffer_json_object_close(wb);
}
static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) {
RRDHOST *host;
- int count = 0;
- buffer_strcat(wb, "\t\"mirrored_hosts\": [\n");
rrd_rdlock();
- rrdhost_foreach_read(host) {
- if (count > 0)
- buffer_strcat(wb, ",\n");
- buffer_sprintf(wb, "\t\t\"%s\"", rrdhost_hostname(host));
- count++;
- }
-
- buffer_strcat(wb, "\n\t],\n\t\"mirrored_hosts_status\": [\n");
- count = 0;
+ buffer_json_member_add_array(wb, "mirrored_hosts");
rrdhost_foreach_read(host)
- {
- if (count > 0)
- buffer_strcat(wb, ",\n");
+ buffer_json_add_array_item_string(wb, rrdhost_hostname(host));
+ buffer_json_array_close(wb);
- buffer_sprintf(
- wb, "\t\t{ \"guid\": \"%s\", \"hostname\": \"%s\", \"reachable\": %s, \"hops\": %d"
- , host->machine_guid
- , rrdhost_hostname(host)
- , (host == localhost || !rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN)) ? "true" : "false"
- , host->system_info ? host->system_info->hops : (host == localhost) ? 0 : 1
- );
-
- rrdhost_aclk_state_lock(host);
- if (host->aclk_state.claimed_id)
- buffer_sprintf(wb, ", \"claim_id\": \"%s\"", host->aclk_state.claimed_id);
- else
- buffer_strcat(wb, ", \"claim_id\": null");
- rrdhost_aclk_state_unlock(host);
-
- if (host->node_id) {
- char node_id_str[GUID_LEN + 1];
- uuid_unparse_lower(*host->node_id, node_id_str);
- buffer_sprintf(wb, ", \"node_id\": \"%s\" }", node_id_str);
- } else
- buffer_strcat(wb, ", \"node_id\": null }");
-
- count++;
+ buffer_json_member_add_array(wb, "mirrored_hosts_status");
+ rrdhost_foreach_read(host) {
+ if ((host == localhost || !rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN))) {
+ web_client_api_request_v1_info_mirrored_hosts_status(wb, host);
+ }
}
+ rrdhost_foreach_read(host) {
+ if ((host != localhost && rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN))) {
+ web_client_api_request_v1_info_mirrored_hosts_status(wb, host);
+ }
+ }
+ buffer_json_array_close(wb);
+
rrd_unlock();
+}
- buffer_strcat(wb, "\n\t],\n");
+void host_labels2json(RRDHOST *host, BUFFER *wb, const char *key) {
+ buffer_json_member_add_object(wb, key);
+ rrdlabels_to_buffer_json_members(host->rrdlabels, wb);
+ buffer_json_object_close(wb);
}
-inline void host_labels2json(RRDHOST *host, BUFFER *wb, size_t indentation) {
- char tabs[11];
+static void host_collectors(RRDHOST *host, BUFFER *wb) {
+ buffer_json_member_add_array(wb, "collectors");
+
+ DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
+ RRDSET *st;
+ char name[500];
- if (indentation > 10)
- indentation = 10;
+ time_t now = now_realtime_sec();
- tabs[0] = '\0';
- while (indentation) {
- strcat(tabs, "\t");
- indentation--;
+ rrdset_foreach_read(st, host) {
+ if (!rrdset_is_available_for_viewers(st))
+ continue;
+
+ sprintf(name, "%s:%s", rrdset_plugin_name(st), rrdset_module_name(st));
+
+ bool old = 0;
+ bool *set = dictionary_set(dict, name, &old, sizeof(bool));
+ if(!*set) {
+ *set = true;
+ st->last_accessed_time_s = now;
+ buffer_json_add_array_item_object(wb);
+ buffer_json_member_add_string(wb, "plugin", rrdset_plugin_name(st));
+ buffer_json_member_add_string(wb, "module", rrdset_module_name(st));
+ buffer_json_object_close(wb);
+ }
}
+ rrdset_foreach_done(st);
+ dictionary_destroy(dict);
- rrdlabels_to_buffer(host->rrdlabels, wb, tabs, ":", "\"", ",\n", NULL, NULL, NULL, NULL);
- buffer_strcat(wb, "\n");
+ buffer_json_array_close(wb);
}
extern int aclk_connected;
-inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
-{
- buffer_strcat(wb, "{\n");
- buffer_sprintf(wb, "\t\"version\": \"%s\",\n", rrdhost_program_version(host));
- buffer_sprintf(wb, "\t\"uid\": \"%s\",\n", host->machine_guid);
+inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb) {
+ buffer_json_initialize(wb, "\"", "\"", 0, true, false);
+ buffer_json_member_add_string(wb, "version", rrdhost_program_version(host));
+ buffer_json_member_add_string(wb, "uid", host->machine_guid);
+
+ buffer_json_member_add_uint64(wb, "hosts-available", rrdhost_hosts_available());
web_client_api_request_v1_info_mirrored_hosts(wb);
- buffer_strcat(wb, "\t\"alarms\": {\n");
- web_client_api_request_v1_info_summary_alarm_statuses(host, wb);
- buffer_strcat(wb, "\t},\n");
-
- buffer_sprintf(wb, "\t\"os_name\": \"%s\",\n", (host->system_info->host_os_name) ? host->system_info->host_os_name : "");
- buffer_sprintf(wb, "\t\"os_id\": \"%s\",\n", (host->system_info->host_os_id) ? host->system_info->host_os_id : "");
- buffer_sprintf(wb, "\t\"os_id_like\": \"%s\",\n", (host->system_info->host_os_id_like) ? host->system_info->host_os_id_like : "");
- buffer_sprintf(wb, "\t\"os_version\": \"%s\",\n", (host->system_info->host_os_version) ? host->system_info->host_os_version : "");
- buffer_sprintf(wb, "\t\"os_version_id\": \"%s\",\n", (host->system_info->host_os_version_id) ? host->system_info->host_os_version_id : "");
- buffer_sprintf(wb, "\t\"os_detection\": \"%s\",\n", (host->system_info->host_os_detection) ? host->system_info->host_os_detection : "");
- buffer_sprintf(wb, "\t\"cores_total\": \"%s\",\n", (host->system_info->host_cores) ? host->system_info->host_cores : "");
- buffer_sprintf(wb, "\t\"total_disk_space\": \"%s\",\n", (host->system_info->host_disk_space) ? host->system_info->host_disk_space : "");
- buffer_sprintf(wb, "\t\"cpu_freq\": \"%s\",\n", (host->system_info->host_cpu_freq) ? host->system_info->host_cpu_freq : "");
- buffer_sprintf(wb, "\t\"ram_total\": \"%s\",\n", (host->system_info->host_ram_total) ? host->system_info->host_ram_total : "");
-
- if (host->system_info->container_os_name)
- buffer_sprintf(wb, "\t\"container_os_name\": \"%s\",\n", host->system_info->container_os_name);
- if (host->system_info->container_os_id)
- buffer_sprintf(wb, "\t\"container_os_id\": \"%s\",\n", host->system_info->container_os_id);
- if (host->system_info->container_os_id_like)
- buffer_sprintf(wb, "\t\"container_os_id_like\": \"%s\",\n", host->system_info->container_os_id_like);
- if (host->system_info->container_os_version)
- buffer_sprintf(wb, "\t\"container_os_version\": \"%s\",\n", host->system_info->container_os_version);
- if (host->system_info->container_os_version_id)
- buffer_sprintf(wb, "\t\"container_os_version_id\": \"%s\",\n", host->system_info->container_os_version_id);
- if (host->system_info->container_os_detection)
- buffer_sprintf(wb, "\t\"container_os_detection\": \"%s\",\n", host->system_info->container_os_detection);
- if (host->system_info->is_k8s_node)
- buffer_sprintf(wb, "\t\"is_k8s_node\": \"%s\",\n", host->system_info->is_k8s_node);
-
- buffer_sprintf(wb, "\t\"kernel_name\": \"%s\",\n", (host->system_info->kernel_name) ? host->system_info->kernel_name : "");
- buffer_sprintf(wb, "\t\"kernel_version\": \"%s\",\n", (host->system_info->kernel_version) ? host->system_info->kernel_version : "");
- buffer_sprintf(wb, "\t\"architecture\": \"%s\",\n", (host->system_info->architecture) ? host->system_info->architecture : "");
- buffer_sprintf(wb, "\t\"virtualization\": \"%s\",\n", (host->system_info->virtualization) ? host->system_info->virtualization : "");
- buffer_sprintf(wb, "\t\"virt_detection\": \"%s\",\n", (host->system_info->virt_detection) ? host->system_info->virt_detection : "");
- buffer_sprintf(wb, "\t\"container\": \"%s\",\n", (host->system_info->container) ? host->system_info->container : "");
- buffer_sprintf(wb, "\t\"container_detection\": \"%s\",\n", (host->system_info->container_detection) ? host->system_info->container_detection : "");
-
- if (host->system_info->cloud_provider_type)
- buffer_sprintf(wb, "\t\"cloud_provider_type\": \"%s\",\n", host->system_info->cloud_provider_type);
- if (host->system_info->cloud_instance_type)
- buffer_sprintf(wb, "\t\"cloud_instance_type\": \"%s\",\n", host->system_info->cloud_instance_type);
- if (host->system_info->cloud_instance_region)
- buffer_sprintf(wb, "\t\"cloud_instance_region\": \"%s\",\n", host->system_info->cloud_instance_region);
-
- buffer_strcat(wb, "\t\"host_labels\": {\n");
- host_labels2json(host, wb, 2);
- buffer_strcat(wb, "\t},\n");
-
- buffer_strcat(wb, "\t\"functions\": {\n");
- host_functions2json(host, wb, 2, "\"", "\"");
- buffer_strcat(wb, "\t},\n");
-
- buffer_strcat(wb, "\t\"collectors\": [");
- chartcollectors2json(host, wb);
- buffer_strcat(wb, "\n\t],\n");
+ web_client_api_request_v1_info_summary_alarm_statuses(host, wb, "alarms");
+
+ buffer_json_member_add_string_or_empty(wb, "os_name", host->system_info->host_os_name);
+ buffer_json_member_add_string_or_empty(wb, "os_id", host->system_info->host_os_id);
+ buffer_json_member_add_string_or_empty(wb, "os_id_like", host->system_info->host_os_id_like);
+ buffer_json_member_add_string_or_empty(wb, "os_version", host->system_info->host_os_version);
+ buffer_json_member_add_string_or_empty(wb, "os_version_id", host->system_info->host_os_version_id);
+ buffer_json_member_add_string_or_empty(wb, "os_detection", host->system_info->host_os_detection);
+ buffer_json_member_add_string_or_empty(wb, "cores_total", host->system_info->host_cores);
+ buffer_json_member_add_string_or_empty(wb, "total_disk_space", host->system_info->host_disk_space);
+ buffer_json_member_add_string_or_empty(wb, "cpu_freq", host->system_info->host_cpu_freq);
+ buffer_json_member_add_string_or_empty(wb, "ram_total", host->system_info->host_ram_total);
+
+ buffer_json_member_add_string_or_omit(wb, "container_os_name", host->system_info->container_os_name);
+ buffer_json_member_add_string_or_omit(wb, "container_os_id", host->system_info->container_os_id);
+ buffer_json_member_add_string_or_omit(wb, "container_os_id_like", host->system_info->container_os_id_like);
+ buffer_json_member_add_string_or_omit(wb, "container_os_version", host->system_info->container_os_version);
+ buffer_json_member_add_string_or_omit(wb, "container_os_version_id", host->system_info->container_os_version_id);
+ buffer_json_member_add_string_or_omit(wb, "container_os_detection", host->system_info->container_os_detection);
+ buffer_json_member_add_string_or_omit(wb, "is_k8s_node", host->system_info->is_k8s_node);
+
+ buffer_json_member_add_string_or_empty(wb, "kernel_name", host->system_info->kernel_name);
+ buffer_json_member_add_string_or_empty(wb, "kernel_version", host->system_info->kernel_version);
+ buffer_json_member_add_string_or_empty(wb, "architecture", host->system_info->architecture);
+ buffer_json_member_add_string_or_empty(wb, "virtualization", host->system_info->virtualization);
+ buffer_json_member_add_string_or_empty(wb, "virt_detection", host->system_info->virt_detection);
+ buffer_json_member_add_string_or_empty(wb, "container", host->system_info->container);
+ buffer_json_member_add_string_or_empty(wb, "container_detection", host->system_info->container_detection);
+
+ buffer_json_member_add_string_or_omit(wb, "cloud_provider_type", host->system_info->cloud_provider_type);
+ buffer_json_member_add_string_or_omit(wb, "cloud_instance_type", host->system_info->cloud_instance_type);
+ buffer_json_member_add_string_or_omit(wb, "cloud_instance_region", host->system_info->cloud_instance_region);
+
+ host_labels2json(host, wb, "host_labels");
+ host_functions2json(host, wb);
+ host_collectors(host, wb);
#ifdef DISABLE_CLOUD
- buffer_strcat(wb, "\t\"cloud-enabled\": false,\n");
+ buffer_json_member_add_boolean(wb, "cloud-enabled", false);
#else
- buffer_sprintf(wb, "\t\"cloud-enabled\": %s,\n",
- appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", 1) ? "true" : "false");
+ buffer_json_member_add_boolean(wb, "cloud-enabled",
+ appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", true));
#endif
#ifdef ENABLE_ACLK
- buffer_strcat(wb, "\t\"cloud-available\": true,\n");
+ buffer_json_member_add_boolean(wb, "cloud-available", true);
#else
- buffer_strcat(wb, "\t\"cloud-available\": false,\n");
+ buffer_json_member_add_boolean(wb, "cloud-available", false);
#endif
+
char *agent_id = get_agent_claimid();
- if (agent_id == NULL)
- buffer_strcat(wb, "\t\"agent-claimed\": false,\n");
- else {
- buffer_strcat(wb, "\t\"agent-claimed\": true,\n");
- freez(agent_id);
- }
+ buffer_json_member_add_boolean(wb, "agent-claimed", agent_id != NULL);
+ freez(agent_id);
+
#ifdef ENABLE_ACLK
- if (aclk_connected) {
- buffer_strcat(wb, "\t\"aclk-available\": true,\n");
- }
- else
+ buffer_json_member_add_boolean(wb, "aclk-available", aclk_connected);
+#else
+ buffer_json_member_add_boolean(wb, "aclk-available", false);
#endif
- buffer_strcat(wb, "\t\"aclk-available\": false,\n"); // Intentionally valid with/without #ifdef above
-
- buffer_strcat(wb, "\t\"memory-mode\": ");
- analytics_get_data(analytics_data.netdata_config_memory_mode, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"multidb-disk-quota\": ");
- analytics_get_data(analytics_data.netdata_config_multidb_disk_quota, wb);
- buffer_strcat(wb, ",\n");
- buffer_strcat(wb, "\t\"page-cache-size\": ");
- analytics_get_data(analytics_data.netdata_config_page_cache_size, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"stream-enabled\": ");
- analytics_get_data(analytics_data.netdata_config_stream_enabled, wb);
- buffer_strcat(wb, ",\n");
+ buffer_json_member_add_string(wb, "memory-mode", rrd_memory_mode_name(host->rrd_memory_mode));
+#ifdef ENABLE_DBENGINE
+ buffer_json_member_add_uint64(wb, "multidb-disk-quota", default_multidb_disk_quota_mb);
+ buffer_json_member_add_uint64(wb, "page-cache-size", default_rrdeng_page_cache_mb);
+#endif // ENABLE_DBENGINE
+ buffer_json_member_add_boolean(wb, "web-enabled", web_server_mode != WEB_SERVER_MODE_NONE);
+ buffer_json_member_add_boolean(wb, "stream-enabled", default_rrdpush_enabled);
#ifdef ENABLE_COMPRESSION
- if(host->sender){
- buffer_strcat(wb, "\t\"stream-compression\": ");
- buffer_strcat(wb, stream_has_capability(host->sender, STREAM_CAP_COMPRESSION) ? "true" : "false");
- buffer_strcat(wb, ",\n");
- }else{
- buffer_strcat(wb, "\t\"stream-compression\": null,\n");
- }
+ buffer_json_member_add_boolean(wb, "stream-compression",
+ host->sender && stream_has_capability(host->sender, STREAM_CAP_COMPRESSION));
#else
- buffer_strcat(wb, "\t\"stream-compression\": null,\n");
-#endif //ENABLE_COMPRESSION
-
- buffer_strcat(wb, "\t\"hosts-available\": ");
- analytics_get_data(analytics_data.netdata_config_hosts_available, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"https-enabled\": ");
- analytics_get_data(analytics_data.netdata_config_https_enabled, wb);
- buffer_strcat(wb, ",\n");
+ buffer_json_member_add_boolean(wb, "stream-compression", false);
+#endif //ENABLE_COMPRESSION
- buffer_strcat(wb, "\t\"buildinfo\": ");
- analytics_get_data(analytics_data.netdata_buildinfo, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"release-channel\": ");
- analytics_get_data(analytics_data.netdata_config_release_channel, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"web-enabled\": ");
- analytics_get_data(analytics_data.netdata_config_web_enabled, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"notification-methods\": ");
- analytics_get_data(analytics_data.netdata_notification_methods, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"exporting-enabled\": ");
- analytics_get_data(analytics_data.netdata_config_exporting_enabled, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"exporting-connectors\": ");
- analytics_get_data(analytics_data.netdata_exporting_connectors, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"allmetrics-prometheus-used\": ");
- analytics_get_data(analytics_data.netdata_allmetrics_prometheus_used, wb);
- buffer_strcat(wb, ",\n");
-
- buffer_strcat(wb, "\t\"allmetrics-shell-used\": ");
- analytics_get_data(analytics_data.netdata_allmetrics_shell_used, wb);
- buffer_strcat(wb, ",\n");
+#ifdef ENABLE_HTTPS
+ buffer_json_member_add_boolean(wb, "https-enabled", true);
+#else
+ buffer_json_member_add_boolean(wb, "https-enabled", false);
+#endif
- buffer_strcat(wb, "\t\"allmetrics-json-used\": ");
- analytics_get_data(analytics_data.netdata_allmetrics_json_used, wb);
- buffer_strcat(wb, ",\n");
+ buffer_json_member_add_quoted_string(wb, "buildinfo", analytics_data.netdata_buildinfo);
+ buffer_json_member_add_quoted_string(wb, "release-channel", analytics_data.netdata_config_release_channel);
+ buffer_json_member_add_quoted_string(wb, "notification-methods", analytics_data.netdata_notification_methods);
- buffer_strcat(wb, "\t\"dashboard-used\": ");
- analytics_get_data(analytics_data.netdata_dashboard_used, wb);
- buffer_strcat(wb, ",\n");
+ buffer_json_member_add_boolean(wb, "exporting-enabled", analytics_data.exporting_enabled);
+ buffer_json_member_add_quoted_string(wb, "exporting-connectors", analytics_data.netdata_exporting_connectors);
- buffer_strcat(wb, "\t\"charts-count\": ");
- analytics_get_data(analytics_data.netdata_charts_count, wb);
- buffer_strcat(wb, ",\n");
+ buffer_json_member_add_uint64(wb, "allmetrics-prometheus-used", analytics_data.prometheus_hits);
+ buffer_json_member_add_uint64(wb, "allmetrics-shell-used", analytics_data.shell_hits);
+ buffer_json_member_add_uint64(wb, "allmetrics-json-used", analytics_data.json_hits);
+ buffer_json_member_add_uint64(wb, "dashboard-used", analytics_data.dashboard_hits);
- buffer_strcat(wb, "\t\"metrics-count\": ");
- analytics_get_data(analytics_data.netdata_metrics_count, wb);
+ buffer_json_member_add_uint64(wb, "charts-count", analytics_data.charts_count);
+ buffer_json_member_add_uint64(wb, "metrics-count", analytics_data.metrics_count);
#if defined(ENABLE_ML)
- buffer_strcat(wb, ",\n");
- char *ml_info = ml_get_host_info(host);
-
- buffer_strcat(wb, "\t\"ml-info\": ");
- buffer_strcat(wb, ml_info);
-
- freez(ml_info);
+ buffer_json_member_add_object(wb, "ml-info");
+ ml_host_get_info(host, wb);
+ buffer_json_object_close(wb);
#endif
- buffer_strcat(wb, "\n}");
+ buffer_json_finalize(wb);
return 0;
}
@@ -1300,17 +1205,16 @@ int web_client_api_request_v1_ml_info(RRDHOST *host, struct web_client *w, char
if (!netdata_ready)
return HTTP_RESP_BACKEND_FETCH_FAILED;
- char *s = ml_get_host_runtime_info(host);
- if (!s)
- s = strdupz("{\"error\": \"json string is empty\" }\n");
-
BUFFER *wb = w->response.data;
buffer_flush(wb);
- wb->contenttype = CT_APPLICATION_JSON;
- buffer_strcat(wb, s);
+ wb->content_type = CT_APPLICATION_JSON;
+
+ buffer_json_initialize(wb, "\"", "\"", 0, true, false);
+ ml_host_get_detection_info(host, wb);
+ buffer_json_finalize(wb);
+
buffer_no_cacheable(wb);
- freez(s);
return HTTP_RESP_OK;
}
@@ -1320,27 +1224,22 @@ int web_client_api_request_v1_ml_models(RRDHOST *host, struct web_client *w, cha
if (!netdata_ready)
return HTTP_RESP_BACKEND_FETCH_FAILED;
- char *s = ml_get_host_models(host);
- if (!s)
- s = strdupz("{\"error\": \"json string is empty\" }\n");
-
BUFFER *wb = w->response.data;
buffer_flush(wb);
- wb->contenttype = CT_APPLICATION_JSON;
- buffer_strcat(wb, s);
+ wb->content_type = CT_APPLICATION_JSON;
+ ml_host_get_models(host, wb);
buffer_no_cacheable(wb);
- freez(s);
return HTTP_RESP_OK;
}
-#endif
+#endif // ENABLE_ML
inline int web_client_api_request_v1_info(RRDHOST *host, struct web_client *w, char *url) {
(void)url;
if (!netdata_ready) return HTTP_RESP_BACKEND_FETCH_FAILED;
BUFFER *wb = w->response.data;
buffer_flush(wb);
- wb->contenttype = CT_APPLICATION_JSON;
+ wb->content_type = CT_APPLICATION_JSON;
web_client_api_request_v1_info_fill_buffer(host, wb);
@@ -1360,94 +1259,19 @@ static int web_client_api_request_v1_aclk_state(RRDHOST *host, struct web_client
buffer_strcat(wb, str);
freez(str);
- wb->contenttype = CT_APPLICATION_JSON;
+ wb->content_type = CT_APPLICATION_JSON;
buffer_no_cacheable(wb);
return HTTP_RESP_OK;
}
-static int web_client_api_request_v1_weights_internal(RRDHOST *host, struct web_client *w, char *url, WEIGHTS_METHOD method, WEIGHTS_FORMAT format) {
- if (!netdata_ready)
- return HTTP_RESP_BACKEND_FETCH_FAILED;
-
- long long baseline_after = 0, baseline_before = 0, after = 0, before = 0, points = 0;
- RRDR_OPTIONS options = RRDR_OPTION_NOT_ALIGNED | RRDR_OPTION_NONZERO | RRDR_OPTION_NULL2ZERO;
- int options_count = 0;
- RRDR_GROUPING group = RRDR_GROUPING_AVERAGE;
- int timeout = 0;
- size_t tier = 0;
- const char *group_options = NULL, *contexts_str = NULL;
-
- while (url) {
- char *value = mystrsep(&url, "&");
- if (!value || !*value)
- continue;
-
- char *name = mystrsep(&value, "=");
- if (!name || !*name)
- continue;
- if (!value || !*value)
- continue;
-
- if (!strcmp(name, "baseline_after"))
- baseline_after = (long long) strtoul(value, NULL, 0);
-
- else if (!strcmp(name, "baseline_before"))
- baseline_before = (long long) strtoul(value, NULL, 0);
-
- else if (!strcmp(name, "after") || !strcmp(name, "highlight_after"))
- after = (long long) strtoul(value, NULL, 0);
-
- else if (!strcmp(name, "before") || !strcmp(name, "highlight_before"))
- before = (long long) strtoul(value, NULL, 0);
-
- else if (!strcmp(name, "points") || !strcmp(name, "max_points"))
- points = (long long) strtoul(value, NULL, 0);
-
- else if (!strcmp(name, "timeout"))
- timeout = (int) strtoul(value, NULL, 0);
-
- else if(!strcmp(name, "group"))
- group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
-
- else if(!strcmp(name, "options")) {
- if(!options_count) options = RRDR_OPTION_NOT_ALIGNED | RRDR_OPTION_NULL2ZERO;
- options |= web_client_api_request_v1_data_options(value);
- options_count++;
- }
-
- else if(!strcmp(name, "method"))
- method = weights_string_to_method(value);
-
- else if(!strcmp(name, "context") || !strcmp(name, "contexts"))
- contexts_str = value;
-
- else if(!strcmp(name, "tier")) {
- tier = str2ul(value);
- if(tier < storage_tiers)
- options |= RRDR_OPTION_SELECTED_TIER;
- else
- tier = 0;
- }
- }
-
- BUFFER *wb = w->response.data;
- buffer_flush(wb);
- wb->contenttype = CT_APPLICATION_JSON;
-
- SIMPLE_PATTERN *contexts = (contexts_str) ? simple_pattern_create(contexts_str, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT) : NULL;
-
- int ret = web_api_v1_weights(host, wb, method, format, group, group_options, baseline_after, baseline_before, after, before, points, options, contexts, tier, timeout);
-
- simple_pattern_free(contexts);
- return ret;
-}
-
int web_client_api_request_v1_metric_correlations(RRDHOST *host, struct web_client *w, char *url) {
- return web_client_api_request_v1_weights_internal(host, w, url, default_metric_correlations_method, WEIGHTS_FORMAT_CHARTS);
+ return web_client_api_request_weights(host, w, url, default_metric_correlations_method,
+ WEIGHTS_FORMAT_CHARTS, 1);
}
int web_client_api_request_v1_weights(RRDHOST *host, struct web_client *w, char *url) {
- return web_client_api_request_v1_weights_internal(host, w, url, WEIGHTS_METHOD_ANOMALY_RATE, WEIGHTS_FORMAT_CONTEXTS);
+ return web_client_api_request_weights(host, w, url, WEIGHTS_METHOD_ANOMALY_RATE,
+ WEIGHTS_FORMAT_CONTEXTS, 1);
}
int web_client_api_request_v1_function(RRDHOST *host, struct web_client *w, char *url) {
@@ -1458,11 +1282,11 @@ int web_client_api_request_v1_function(RRDHOST *host, struct web_client *w, char
const char *function = NULL;
while (url) {
- char *value = mystrsep(&url, "&");
+ char *value = strsep_skip_consecutive_separators(&url, "&");
if (!value || !*value)
continue;
- char *name = mystrsep(&value, "=");
+ char *name = strsep_skip_consecutive_separators(&value, "=");
if (!name || !*name)
continue;
@@ -1475,7 +1299,7 @@ int web_client_api_request_v1_function(RRDHOST *host, struct web_client *w, char
BUFFER *wb = w->response.data;
buffer_flush(wb);
- wb->contenttype = CT_APPLICATION_JSON;
+ wb->content_type = CT_APPLICATION_JSON;
buffer_no_cacheable(wb);
return rrd_call_function_and_wait(host, wb, timeout, function);
@@ -1487,12 +1311,12 @@ int web_client_api_request_v1_functions(RRDHOST *host, struct web_client *w, cha
BUFFER *wb = w->response.data;
buffer_flush(wb);
- wb->contenttype = CT_APPLICATION_JSON;
+ wb->content_type = CT_APPLICATION_JSON;
buffer_no_cacheable(wb);
- buffer_strcat(wb, "{\n");
- host_functions2json(host, wb, 1, "\"", "\"");
- buffer_strcat(wb, "}");
+ buffer_json_initialize(wb, "\"", "\"", 0, true, false);
+ host_functions2json(host, wb);
+ buffer_json_finalize(wb);
return HTTP_RESP_OK;
}
@@ -1576,7 +1400,7 @@ int web_client_api_request_v1_dbengine_stats(RRDHOST *host __maybe_unused, struc
return HTTP_RESP_NOT_FOUND;
}
- wb->contenttype = CT_APPLICATION_JSON;
+ wb->content_type = CT_APPLICATION_JSON;
buffer_no_cacheable(wb);
buffer_strcat(wb, "{");
for(size_t tier = 0; tier < storage_tiers ;tier++) {
@@ -1596,85 +1420,55 @@ int web_client_api_request_v1_dbengine_stats(RRDHOST *host __maybe_unused, struc
#define ACL_DEV_OPEN_ACCESS 0
#endif
-static struct api_command {
- const char *command;
- uint32_t hash;
- WEB_CLIENT_ACL acl;
- int (*callback)(RRDHOST *host, struct web_client *w, char *url);
-} api_commands[] = {
- { "info", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_info },
- { "data", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_data },
- { "chart", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_chart },
- { "charts", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_charts },
- { "context", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_context },
- { "contexts", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_contexts },
+static struct web_api_command api_commands_v1[] = {
+ { "info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_info },
+ { "data", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_data },
+ { "chart", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_chart },
+ { "charts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_charts },
+ { "context", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_context },
+ { "contexts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_contexts },
// registry checks the ACL by itself, so we allow everything
{ "registry", 0, WEB_CLIENT_ACL_NOCHECK, web_client_api_request_v1_registry },
// badges can be fetched with both dashboard and badge permissions
- { "badge.svg", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_badge },
+ { "badge.svg", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC | WEB_CLIENT_ACL_BADGE, web_client_api_request_v1_badge },
- { "alarms", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_alarms },
- { "alarms_values", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_alarms_values },
- { "alarm_log", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_alarm_log },
- { "alarm_variables", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_alarm_variables },
- { "alarm_count", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_alarm_count },
- { "allmetrics", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_allmetrics },
+ { "alarms", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarms },
+ { "alarms_values", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarms_values },
+ { "alarm_log", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarm_log },
+ { "alarm_variables", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarm_variables },
+ { "alarm_count", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarm_count },
+ { "allmetrics", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_allmetrics },
#if defined(ENABLE_ML)
- { "ml_info", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_ml_info },
- { "ml_models", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_ml_models },
+ { "ml_info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_ml_info },
+ { "ml_models", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_ml_models },
#endif
{ "manage/health", 0, WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_mgmt_health },
- { "aclk", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_aclk_state },
- { "metric_correlations", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_metric_correlations },
- { "weights", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_weights },
+ { "aclk", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_aclk_state },
+ { "metric_correlations", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_metric_correlations },
+ { "weights", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_weights },
{ "function", 0, WEB_CLIENT_ACL_ACLK | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_function },
{ "functions", 0, WEB_CLIENT_ACL_ACLK | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_functions },
- { "dbengine_stats", 0, WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_dbengine_stats },
+ { "dbengine_stats", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_dbengine_stats },
// terminator
{ NULL, 0, WEB_CLIENT_ACL_NONE, NULL },
};
-inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url) {
+inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url_path_endpoint) {
static int initialized = 0;
- int i;
if(unlikely(initialized == 0)) {
initialized = 1;
- for(i = 0; api_commands[i].command ; i++)
- api_commands[i].hash = simple_hash(api_commands[i].command);
+ for(int i = 0; api_commands_v1[i].command ; i++)
+ api_commands_v1[i].hash = simple_hash(api_commands_v1[i].command);
}
- // get the command
- if(url) {
- debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, url);
- uint32_t hash = simple_hash(url);
-
- for(i = 0; api_commands[i].command ;i++) {
- if(unlikely(hash == api_commands[i].hash && !strcmp(url, api_commands[i].command))) {
- if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl))
- return web_client_permission_denied(w);
-
- //return api_commands[i].callback(host, w, url);
- return api_commands[i].callback(host, w, (w->decoded_query_string + 1));
- }
- }
-
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Unsupported v1 API command: ");
- buffer_strcat_htmlescape(w->response.data, url);
- return HTTP_RESP_NOT_FOUND;
- }
- else {
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Which API v1 command?");
- return HTTP_RESP_BAD_REQUEST;
- }
+ return web_client_api_request_vX(host, w, url_path_endpoint, api_commands_v1);
}