summaryrefslogtreecommitdiffstats
path: root/src/web/api/web_api_v1.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/web/api/web_api_v1.c (renamed from web/api/web_api_v1.c)556
1 files changed, 460 insertions, 96 deletions
diff --git a/web/api/web_api_v1.c b/src/web/api/web_api_v1.c
index e08f8aa2f..386221d61 100644
--- a/web/api/web_api_v1.c
+++ b/src/web/api/web_api_v1.c
@@ -8,17 +8,20 @@ static struct {
const char *name;
uint32_t hash;
RRDR_OPTIONS value;
-} api_v1_data_options[] = {
+} rrdr_options[] = {
{ "nonzero" , 0 , RRDR_OPTION_NONZERO}
, {"flip" , 0 , RRDR_OPTION_REVERSED}
, {"reversed" , 0 , RRDR_OPTION_REVERSED}
, {"reverse" , 0 , RRDR_OPTION_REVERSED}
, {"jsonwrap" , 0 , RRDR_OPTION_JSON_WRAP}
- , {"min2max" , 0 , RRDR_OPTION_MIN2MAX}
+ , {"min2max" , 0 , RRDR_OPTION_DIMS_MIN2MAX} // rrdr2value() only
+ , {"average" , 0 , RRDR_OPTION_DIMS_AVERAGE} // rrdr2value() only
+ , {"min" , 0 , RRDR_OPTION_DIMS_MIN} // rrdr2value() only
+ , {"max" , 0 , RRDR_OPTION_DIMS_MAX} // rrdr2value() only
, {"ms" , 0 , RRDR_OPTION_MILLISECONDS}
, {"milliseconds" , 0 , RRDR_OPTION_MILLISECONDS}
- , {"abs" , 0 , RRDR_OPTION_ABSOLUTE}
, {"absolute" , 0 , RRDR_OPTION_ABSOLUTE}
+ , {"abs" , 0 , RRDR_OPTION_ABSOLUTE}
, {"absolute_sum" , 0 , RRDR_OPTION_ABSOLUTE}
, {"absolute-sum" , 0 , RRDR_OPTION_ABSOLUTE}
, {"display_absolute" , 0 , RRDR_OPTION_DISPLAY_ABS}
@@ -108,13 +111,15 @@ static struct {
uint32_t hash;
DATASOURCE_FORMAT value;
} api_v1_data_google_formats[] = {
- // this is not error - when google requests json, it expects javascript
- // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source#responseformat
- { "json" , 0 , DATASOURCE_DATATABLE_JSONP}
- , {"html" , 0 , DATASOURCE_HTML}
- , {"csv" , 0 , DATASOURCE_CSV}
- , {"tsv-excel", 0 , DATASOURCE_TSV}
- , { NULL, 0, 0}
+ // this is not an error - when Google requests json, it expects javascript
+ // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source#responseformat
+ {"json", 0, DATASOURCE_DATATABLE_JSONP}
+ , {"html", 0, DATASOURCE_HTML}
+ , {"csv", 0, DATASOURCE_CSV}
+ , {"tsv-excel", 0, DATASOURCE_TSV}
+
+ // terminator
+ , {NULL, 0, 0}
};
void web_client_api_v1_init(void) {
@@ -123,8 +128,8 @@ void web_client_api_v1_init(void) {
for(i = 0; contexts_v2_alert_status[i].name ; i++)
contexts_v2_alert_status[i].hash = simple_hash(contexts_v2_alert_status[i].name);
- for(i = 0; api_v1_data_options[i].name ; i++)
- api_v1_data_options[i].hash = simple_hash(api_v1_data_options[i].name);
+ for(i = 0; rrdr_options[i].name ; i++)
+ rrdr_options[i].hash = simple_hash(rrdr_options[i].name);
for(i = 0; contexts_v2_options[i].name ; i++)
contexts_v2_options[i].hash = simple_hash(contexts_v2_options[i].name);
@@ -157,7 +162,7 @@ char *get_mgmt_api_key(void) {
return guid;
// read it from disk
- int fd = open(api_key_filename, O_RDONLY);
+ int fd = open(api_key_filename, O_RDONLY | O_CLOEXEC);
if(fd != -1) {
char buf[GUID_LEN + 1];
if(read(fd, buf, GUID_LEN) != GUID_LEN)
@@ -183,7 +188,7 @@ char *get_mgmt_api_key(void) {
guid[GUID_LEN] = '\0';
// save it
- fd = open(api_key_filename, O_WRONLY|O_CREAT|O_TRUNC, 444);
+ fd = open(api_key_filename, O_WRONLY|O_CREAT|O_TRUNC | O_CLOEXEC, 444);
if(fd == -1) {
netdata_log_error("Cannot create unique management API key file '%s'. Please adjust config parameter 'netdata management api key file' to a proper path and file.", api_key_filename);
goto temp_key;
@@ -209,21 +214,30 @@ void web_client_api_v1_management_init(void) {
api_secret = get_mgmt_api_key();
}
-inline RRDR_OPTIONS web_client_api_request_v1_data_options(char *o) {
+inline RRDR_OPTIONS rrdr_options_parse_one(const char *o) {
+ RRDR_OPTIONS ret = 0;
+
+ if(!o || !*o) return ret;
+
+ uint32_t hash = simple_hash(o);
+ int i;
+ for(i = 0; rrdr_options[i].name ; i++) {
+ if (unlikely(hash == rrdr_options[i].hash && !strcmp(o, rrdr_options[i].name))) {
+ ret |= rrdr_options[i].value;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+inline RRDR_OPTIONS rrdr_options_parse(char *o) {
RRDR_OPTIONS ret = 0;
char *tok;
while(o && *o && (tok = strsep_skip_consecutive_separators(&o, ", |"))) {
if(!*tok) continue;
-
- uint32_t hash = simple_hash(tok);
- int i;
- for(i = 0; api_v1_data_options[i].name ; i++) {
- if (unlikely(hash == api_v1_data_options[i].hash && !strcmp(tok, api_v1_data_options[i].name))) {
- ret |= api_v1_data_options[i].value;
- break;
- }
- }
+ ret |= rrdr_options_parse_one(tok);
}
return ret;
@@ -301,14 +315,14 @@ void web_client_api_request_v2_contexts_options_to_buffer_json_array(BUFFER *wb,
buffer_json_array_close(wb);
}
-void web_client_api_request_v1_data_options_to_buffer_json_array(BUFFER *wb, const char *key, RRDR_OPTIONS options) {
+void rrdr_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
- 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;
+ for(int i = 0; rrdr_options[i].name ; i++) {
+ if (unlikely((rrdr_options[i].value & options) && !(rrdr_options[i].value & used))) {
+ const char *name = rrdr_options[i].name;
+ used |= rrdr_options[i].value;
buffer_json_add_array_item_string(wb, name);
}
@@ -317,16 +331,30 @@ void web_client_api_request_v1_data_options_to_buffer_json_array(BUFFER *wb, con
buffer_json_array_close(wb);
}
+void rrdr_options_to_buffer(BUFFER *wb, RRDR_OPTIONS options) {
+ RRDR_OPTIONS used = 0; // to prevent adding duplicates
+ size_t added = 0;
+ for(int i = 0; rrdr_options[i].name ; i++) {
+ if (unlikely((rrdr_options[i].value & options) && !(rrdr_options[i].value & used))) {
+ const char *name = rrdr_options[i].name;
+ used |= rrdr_options[i].value;
+
+ if(added++) buffer_strcat(wb, " ");
+ buffer_strcat(wb, name);
+ }
+ }
+}
+
void web_client_api_request_v1_data_options_to_string(char *buf, size_t size, RRDR_OPTIONS options) {
char *write = buf;
char *end = &buf[size - 1];
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;
+ for(int i = 0; rrdr_options[i].name ; i++) {
+ if (unlikely((rrdr_options[i].value & options) && !(rrdr_options[i].value & used))) {
+ const char *name = rrdr_options[i].name;
+ used |= rrdr_options[i].value;
if(added && write < end)
*write++ = ',';
@@ -512,6 +540,52 @@ inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client
return ret;
}
+static inline int web_client_api_request_variable(RRDHOST *host, struct web_client *w, char *url) {
+ int ret = HTTP_RESP_BAD_REQUEST;
+ char *chart = NULL;
+ char *variable = NULL;
+
+ buffer_flush(w->response.data);
+
+ while(url) {
+ char *value = strsep_skip_consecutive_separators(&url, "&");
+ if(!value || !*value) continue;
+
+ char *name = strsep_skip_consecutive_separators(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "chart")) chart = value;
+ else if(!strcmp(name, "variable")) variable = value;
+ }
+
+ if(!chart || !*chart || !variable || !*variable) {
+ buffer_sprintf(w->response.data, "A chart= and a variable= are required.");
+ goto cleanup;
+ }
+
+ RRDSET *st = rrdset_find(host, chart);
+ if(!st) st = rrdset_find_byname(host, chart);
+ if(!st) {
+ buffer_strcat(w->response.data, "Chart is not found: ");
+ buffer_strcat_htmlescape(w->response.data, chart);
+ ret = HTTP_RESP_NOT_FOUND;
+ goto cleanup;
+ }
+
+ w->response.data->content_type = CT_APPLICATION_JSON;
+ st->last_accessed_time_s = now_realtime_sec();
+ alert_variable_lookup_trace(host, st, variable, w->response.data);
+
+ return HTTP_RESP_OK;
+
+cleanup:
+ return ret;
+}
+
inline int web_client_api_request_v1_alarm_variables(RRDHOST *host, struct web_client *w, char *url) {
return web_client_api_request_single_chart(host, w, url, health_api_v1_chart_variables2json);
}
@@ -721,7 +795,7 @@ static inline int web_client_api_request_v1_data(RRDHOST *host, struct web_clien
format = web_client_api_request_v1_data_format(value);
}
else if(!strcmp(name, "options")) {
- options |= web_client_api_request_v1_data_options(value);
+ options |= rrdr_options_parse(value);
}
else if(!strcmp(name, "callback")) {
responseHandler = value;
@@ -822,6 +896,7 @@ static inline int web_client_api_request_v1_data(RRDHOST *host, struct web_clien
.priority = STORAGE_PRIORITY_NORMAL,
.interrupt_callback = web_client_interrupt_callback,
.interrupt_callback_data = w,
+ .transaction = &w->transaction,
};
qt = query_target_create(&qtr);
@@ -856,7 +931,7 @@ static inline int web_client_api_request_v1_data(RRDHOST *host, struct web_clien
responseHandler,
google_version,
google_reqId,
- (int64_t)st->last_updated.tv_sec);
+ (int64_t)(st ? st->last_updated.tv_sec : 0));
}
else if(format == DATASOURCE_JSONP) {
if(responseHandler == NULL)
@@ -941,7 +1016,7 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
if(cookie)
strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], UUID_STR_LEN - 1);
- else if(extract_bearer_token_from_request(w, person_guid, sizeof(person_guid)) != BEARER_STATUS_EXTRACTED_FROM_HEADER)
+ else if(!extract_bearer_token_from_request(w, person_guid, sizeof(person_guid)))
person_guid[0] = '\0';
char action = '\0';
@@ -1018,13 +1093,13 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
if(unlikely(action == 'H')) {
// HELLO request, dashboard ACL
analytics_log_dashboard();
- if(unlikely(!web_client_can_access_dashboard(w)))
- return web_client_permission_denied(w);
+ if(unlikely(!http_can_access_dashboard(w)))
+ return web_client_permission_denied_acl(w);
}
else {
// everything else, registry ACL
- if(unlikely(!web_client_can_access_registry(w)))
- return web_client_permission_denied(w);
+ if(unlikely(!http_can_access_registry(w)))
+ return web_client_permission_denied_acl(w);
if(unlikely(do_not_track)) {
buffer_flush(w->response.data);
@@ -1325,21 +1400,6 @@ int web_client_api_request_v1_ml_info(RRDHOST *host, struct web_client *w, char
return HTTP_RESP_OK;
}
-
-int web_client_api_request_v1_ml_models(RRDHOST *host, struct web_client *w, char *url) {
- (void) url;
-
- if (!netdata_ready)
- return HTTP_RESP_SERVICE_UNAVAILABLE;
-
- BUFFER *wb = w->response.data;
- buffer_flush(wb);
- wb->content_type = CT_APPLICATION_JSON;
- ml_host_get_models(host, wb);
- buffer_no_cacheable(wb);
-
- return HTTP_RESP_OK;
-}
#endif // ENABLE_ML
inline int web_client_api_request_v1_info(RRDHOST *host, struct web_client *w, char *url) {
@@ -1373,13 +1433,17 @@ static int web_client_api_request_v1_aclk_state(RRDHOST *host, struct web_client
}
int web_client_api_request_v1_metric_correlations(RRDHOST *host, struct web_client *w, char *url) {
- return web_client_api_request_weights(host, w, url, default_metric_correlations_method,
- WEIGHTS_FORMAT_CHARTS, 1);
+ 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_weights(host, w, url, WEIGHTS_METHOD_ANOMALY_RATE,
- WEIGHTS_FORMAT_CONTEXTS, 1);
+ return web_client_api_request_weights(host, w, url, WEIGHTS_METHOD_ANOMALY_RATE, WEIGHTS_FORMAT_CONTEXTS, 1);
+}
+
+static void web_client_progress_functions_update(void *data, size_t done, size_t all) {
+ // handle progress updates from the plugin
+ struct web_client *w = data;
+ query_progress_functions_update(&w->transaction, done, all);
}
int web_client_api_request_v1_function(RRDHOST *host, struct web_client *w, char *url) {
@@ -1413,9 +1477,14 @@ int web_client_api_request_v1_function(RRDHOST *host, struct web_client *w, char
char transaction[UUID_COMPACT_STR_LEN];
uuid_unparse_lower_compact(w->transaction, transaction);
- return rrd_function_run(host, wb, timeout, function, true, transaction,
+ CLEAN_BUFFER *source = buffer_create(100, NULL);
+ web_client_source2buffer(w, source);
+
+ return rrd_function_run(host, wb, timeout, w->access, function, true, transaction,
NULL, NULL,
- web_client_interrupt_callback, w, NULL);
+ web_client_progress_functions_update, w,
+ web_client_interrupt_callback, w, NULL,
+ buffer_tostring(source));
}
int web_client_api_request_v1_functions(RRDHOST *host, struct web_client *w, char *url __maybe_unused) {
@@ -1434,6 +1503,113 @@ int web_client_api_request_v1_functions(RRDHOST *host, struct web_client *w, cha
return HTTP_RESP_OK;
}
+void web_client_source2buffer(struct web_client *w, BUFFER *source) {
+ if(web_client_flag_check(w, WEB_CLIENT_FLAG_AUTH_CLOUD))
+ buffer_sprintf(source, "method=NC");
+ else if(web_client_flag_check(w, WEB_CLIENT_FLAG_AUTH_BEARER))
+ buffer_sprintf(source, "method=api-bearer");
+ else
+ buffer_sprintf(source, "method=api");
+
+ if(web_client_flag_check(w, WEB_CLIENT_FLAG_AUTH_GOD))
+ buffer_strcat(source, ",role=god");
+ else
+ buffer_sprintf(source, ",role=%s", http_id2user_role(w->user_role));
+
+ buffer_sprintf(source, ",permissions="HTTP_ACCESS_FORMAT, (HTTP_ACCESS_FORMAT_CAST)w->access);
+
+ if(w->auth.client_name[0])
+ buffer_sprintf(source, ",user=%s", w->auth.client_name);
+
+ if(!uuid_is_null(w->auth.cloud_account_id)) {
+ char uuid_str[UUID_COMPACT_STR_LEN];
+ uuid_unparse_lower_compact(w->auth.cloud_account_id, uuid_str);
+ buffer_sprintf(source, ",account=%s", uuid_str);
+ }
+
+ if(w->client_ip[0])
+ buffer_sprintf(source, ",ip=%s", w->client_ip);
+
+ if(w->forwarded_for)
+ buffer_sprintf(source, ",forwarded_for=%s", w->forwarded_for);
+}
+
+static int web_client_api_request_v1_config(RRDHOST *host, struct web_client *w, char *url __maybe_unused) {
+ char *action = "tree";
+ char *path = "/";
+ char *id = NULL;
+ char *add_name = NULL;
+ int timeout = 120;
+
+ while(url) {
+ char *value = strsep_skip_consecutive_separators(&url, "&");
+ if(!value || !*value) continue;
+
+ char *name = strsep_skip_consecutive_separators(&value, "=");
+ if(!name || !*name) continue;
+ if(!value || !*value) continue;
+
+ // name and value are now the parameters
+ // they are not null and not empty
+
+ if(!strcmp(name, "action"))
+ action = value;
+ else if(!strcmp(name, "path"))
+ path = value;
+ else if(!strcmp(name, "id"))
+ id = value;
+ else if(!strcmp(name, "name"))
+ add_name = value;
+ else if(!strcmp(name, "timeout")) {
+ timeout = (int)strtol(value, NULL, 10);
+ if(timeout < 10)
+ timeout = 10;
+ }
+ }
+
+ char transaction[UUID_COMPACT_STR_LEN];
+ uuid_unparse_lower_compact(w->transaction, transaction);
+
+ size_t len = strlen(action) + (id ? strlen(id) : 0) + strlen(path) + (add_name ? strlen(add_name) : 0) + 100;
+
+ char cmd[len];
+ if(strcmp(action, "tree") == 0)
+ snprintfz(cmd, sizeof(cmd), PLUGINSD_FUNCTION_CONFIG " tree '%s' '%s'", path, id?id:"");
+ else {
+ DYNCFG_CMDS c = dyncfg_cmds2id(action);
+ if(!id || !*id || !dyncfg_is_valid_id(id)) {
+ rrd_call_function_error(w->response.data, "invalid id given", HTTP_RESP_BAD_REQUEST);
+ return HTTP_RESP_BAD_REQUEST;
+ }
+ if(c == DYNCFG_CMD_NONE) {
+ rrd_call_function_error(w->response.data, "invalid action given", HTTP_RESP_BAD_REQUEST);
+ return HTTP_RESP_BAD_REQUEST;
+ }
+ else if(c == DYNCFG_CMD_ADD) {
+ if(!add_name || !*add_name || !dyncfg_is_valid_id(add_name)) {
+ rrd_call_function_error(w->response.data, "invalid name given", HTTP_RESP_BAD_REQUEST);
+ return HTTP_RESP_BAD_REQUEST;
+ }
+ snprintfz(cmd, sizeof(cmd), PLUGINSD_FUNCTION_CONFIG " %s %s %s", id, dyncfg_id2cmd_one(c), add_name);
+ }
+ else
+ snprintfz(cmd, sizeof(cmd), PLUGINSD_FUNCTION_CONFIG " %s %s", id, dyncfg_id2cmd_one(c));
+ }
+
+ CLEAN_BUFFER *source = buffer_create(100, NULL);
+ web_client_source2buffer(w, source);
+
+ buffer_flush(w->response.data);
+ int code = rrd_function_run(host, w->response.data, timeout, w->access, cmd,
+ true, transaction,
+ NULL, NULL,
+ web_client_progress_functions_update, w,
+ web_client_interrupt_callback, w,
+ w->payload, buffer_tostring(source));
+
+ return code;
+}
+
#ifndef ENABLE_DBENGINE
int web_client_api_request_v1_dbengine_stats(RRDHOST *host __maybe_unused, struct web_client *w __maybe_unused, char *url __maybe_unused) {
return HTTP_RESP_NOT_FOUND;
@@ -1540,50 +1716,238 @@ int web_client_api_request_v1_mgmt(RRDHOST *host, struct web_client *w, char *ur
}
needle += strlen(HLT_MGM);
if (*needle != '\0') {
- buffer_strcat(w->response.data, "Invalid management request. Curently only 'health' is supported.");
+ buffer_strcat(w->response.data, "Invalid management request. Currently only 'health' is supported.");
return HTTP_RESP_NOT_FOUND;
}
return web_client_api_request_v1_mgmt_health(host, w, url);
}
static struct web_api_command api_commands_v1[] = {
- { "info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_info, 0 },
- { "data", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_data, 0 },
- { "chart", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_chart, 0 },
- { "charts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_charts, 0 },
- { "context", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_context, 0 },
- { "contexts", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_contexts, 0 },
-
+ // time-series data APIs
+ {
+ .api = "data",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_data,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "weights",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_weights,
+ .allow_subpaths = 0
+ },
+ {
+ // deprecated - do not use anymore - use "weights"
+ .api = "metric_correlations",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_metric_correlations,
+ .allow_subpaths = 0
+ },
+ {
+ // exporting API
+ .api = "allmetrics",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_allmetrics,
+ .allow_subpaths = 0
+ },
+ {
+ // badges can be fetched with both dashboard and badge ACL
+ .api = "badge.svg",
+ .hash = 0,
+ .acl = HTTP_ACL_BADGES,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_badge,
+ .allow_subpaths = 0
+ },
+
+ // alerts APIs
+ {
+ .api = "alarms",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_alarms,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "alarms_values",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_alarms_values,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "alarm_log",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_alarm_log,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "alarm_variables",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_alarm_variables,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "variable",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_variable,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "alarm_count",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_alarm_count,
+ .allow_subpaths = 0
+ },
+
+ // functions APIs - they check permissions per function call
+ {
+ .api = "function",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_function,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "functions",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_functions,
+ .allow_subpaths = 0
+ },
+
+ // time-series metadata APIs
+ {
+ .api = "chart",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_chart,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "charts",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_charts,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "context",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_context,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "contexts",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_contexts,
+ .allow_subpaths = 0
+ },
+
+ // registry APIs
+ {
// registry checks the ACL by itself, so we allow everything
- { "registry", 0, WEB_CLIENT_ACL_NOCHECK, web_client_api_request_v1_registry, 0 },
-
- // badges can be fetched with both dashboard and badge permissions
- { "badge.svg", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC | WEB_CLIENT_ACL_BADGE, web_client_api_request_v1_badge, 0 },
-
- { "alarms", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarms, 0 },
- { "alarms_values", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarms_values, 0 },
- { "alarm_log", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarm_log, 0 },
- { "alarm_variables", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarm_variables, 0 },
- { "alarm_count", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_alarm_count, 0 },
- { "allmetrics", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_allmetrics, 0 },
+ .api = "registry",
+ .hash = 0,
+ .acl = HTTP_ACL_NONE, // it manages acl by itself
+ .access = HTTP_ACCESS_NONE, // it manages access by itself
+ .callback = web_client_api_request_v1_registry,
+ .allow_subpaths = 0
+ },
+
+ // agent information APIs
+ {
+ .api = "info",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_info,
+ .allow_subpaths = 0
+ },
+ {
+ .api = "aclk",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_aclk_state,
+ .allow_subpaths = 0
+ },
+ {
+ // deprecated - use /api/v2/info
+ .api = "dbengine_stats",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_dbengine_stats,
+ .allow_subpaths = 0
+ },
+
+ // dyncfg APIs
+ {
+ .api = "config",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_config,
+ .allow_subpaths = 0
+ },
#if defined(ENABLE_ML)
- { "ml_info", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_ml_info, 0 },
- // { "ml_models", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_ml_models },
+ {
+ .api = "ml_info",
+ .hash = 0,
+ .acl = HTTP_ACL_DASHBOARD,
+ .access = HTTP_ACCESS_ANONYMOUS_DATA,
+ .callback = web_client_api_request_v1_ml_info,
+ .allow_subpaths = 0
+ },
#endif
- {"manage", 0, WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_ACLK, web_client_api_request_v1_mgmt, 1 },
- { "aclk", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_aclk_state, 0 },
- { "metric_correlations", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_metric_correlations, 0 },
- { "weights", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_weights, 0 },
-
- {"function", 0, WEB_CLIENT_ACL_ACLK_WEBRTC_DASHBOARD_WITH_BEARER | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_function, 0 },
- {"functions", 0, WEB_CLIENT_ACL_ACLK_WEBRTC_DASHBOARD_WITH_BEARER | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_functions, 0 },
-
- { "dbengine_stats", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_dbengine_stats, 0 },
-
- // terminator
- { NULL, 0, WEB_CLIENT_ACL_NONE, NULL, 0 },
+ {
+ // deprecated
+ .api = "manage",
+ .hash = 0,
+ .acl = HTTP_ACL_MANAGEMENT,
+ .access = HTTP_ACCESS_NONE, // it manages access by itself
+ .callback = web_client_api_request_v1_mgmt,
+ .allow_subpaths = 1
+ },
+
+ {
+ // terminator - keep this last on this list
+ .api = NULL,
+ .hash = 0,
+ .acl = HTTP_ACL_NONE,
+ .access = HTTP_ACCESS_NONE,
+ .callback = NULL,
+ .allow_subpaths = 0
+ },
};
inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url_path_endpoint) {
@@ -1592,8 +1956,8 @@ inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *
if(unlikely(initialized == 0)) {
initialized = 1;
- for(int i = 0; api_commands_v1[i].command ; i++)
- api_commands_v1[i].hash = simple_hash(api_commands_v1[i].command);
+ for(int i = 0; api_commands_v1[i].api ; i++)
+ api_commands_v1[i].hash = simple_hash(api_commands_v1[i].api);
}
return web_client_api_request_vX(host, w, url_path_endpoint, api_commands_v1);