From cd4377fab21e0f500bef7f06543fa848a039c1e0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 20 Jul 2023 06:50:01 +0200 Subject: Merging upstream version 1.41.0. Signed-off-by: Daniel Baumann --- web/api/web_api_v1.c | 193 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 146 insertions(+), 47 deletions(-) (limited to 'web/api/web_api_v1.c') diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c index 637329696..1e4f9c41c 100644 --- a/web/api/web_api_v1.c +++ b/web/api/web_api_v1.c @@ -50,6 +50,35 @@ static struct { , {NULL , 0 , 0} }; +static struct { + const char *name; + uint32_t hash; + CONTEXTS_V2_OPTIONS value; +} contexts_v2_options[] = { + {"minify" , 0 , CONTEXT_V2_OPTION_MINIFY} + , {"debug" , 0 , CONTEXT_V2_OPTION_DEBUG} + , {"config" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_CONFIGURATIONS} + , {"instances" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_INSTANCES} + , {"values" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_VALUES} + , {"summary" , 0 , CONTEXT_V2_OPTION_ALERTS_WITH_SUMMARY} + , {NULL , 0 , 0} +}; + +static struct { + const char *name; + uint32_t hash; + CONTEXTS_V2_ALERT_STATUS value; +} contexts_v2_alert_status[] = { + {"uninitialized" , 0 , CONTEXT_V2_ALERT_UNINITIALIZED} + , {"undefined" , 0 , CONTEXT_V2_ALERT_UNDEFINED} + , {"clear" , 0 , CONTEXT_V2_ALERT_CLEAR} + , {"raised" , 0 , CONTEXT_V2_ALERT_RAISED} + , {"active" , 0 , CONTEXT_V2_ALERT_RAISED} + , {"warning" , 0 , CONTEXT_V2_ALERT_WARNING} + , {"critical" , 0 , CONTEXT_V2_ALERT_CRITICAL} + , {NULL , 0 , 0} +}; + static struct { const char *name; uint32_t hash; @@ -91,9 +120,15 @@ static struct { void web_client_api_v1_init(void) { int i; + 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; contexts_v2_options[i].name ; i++) + contexts_v2_options[i].hash = simple_hash(contexts_v2_options[i].name); + for(i = 0; api_v1_data_formats[i].name ; i++) api_v1_data_formats[i].hash = simple_hash(api_v1_data_formats[i].name); @@ -126,11 +161,11 @@ char *get_mgmt_api_key(void) { if(fd != -1) { char buf[GUID_LEN + 1]; if(read(fd, buf, GUID_LEN) != GUID_LEN) - error("Failed to read management API key from '%s'", api_key_filename); + netdata_log_error("Failed to read management API key from '%s'", api_key_filename); else { buf[GUID_LEN] = '\0'; if(regenerate_guid(buf, guid) == -1) { - error("Failed to validate management API key '%s' from '%s'.", + netdata_log_error("Failed to validate management API key '%s' from '%s'.", buf, api_key_filename); guid[0] = '\0'; @@ -150,12 +185,12 @@ char *get_mgmt_api_key(void) { // save it fd = open(api_key_filename, O_WRONLY|O_CREAT|O_TRUNC, 444); if(fd == -1) { - 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); + 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; } if(write(fd, guid, GUID_LEN) != GUID_LEN) { - error("Cannot write the unique management API key file '%s'. Please adjust config parameter 'netdata management api key file' to a proper path and file with enough space left.", api_key_filename); + netdata_log_error("Cannot write the unique management API key file '%s'. Please adjust config parameter 'netdata management api key file' to a proper path and file with enough space left.", api_key_filename); close(fd); goto temp_key; } @@ -166,7 +201,7 @@ char *get_mgmt_api_key(void) { return guid; temp_key: - info("You can still continue to use the alarm management API using the authorization token %s during this Netdata session only.", guid); + netdata_log_info("You can still continue to use the alarm management API using the authorization token %s during this Netdata session only.", guid); return guid; } @@ -175,7 +210,7 @@ void web_client_api_v1_management_init(void) { } inline RRDR_OPTIONS web_client_api_request_v1_data_options(char *o) { - RRDR_OPTIONS ret = 0x00000000; + RRDR_OPTIONS ret = 0; char *tok; while(o && *o && (tok = strsep_skip_consecutive_separators(&o, ", |"))) { @@ -194,6 +229,78 @@ inline RRDR_OPTIONS web_client_api_request_v1_data_options(char *o) { return ret; } +inline CONTEXTS_V2_OPTIONS web_client_api_request_v2_context_options(char *o) { + CONTEXTS_V2_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; contexts_v2_options[i].name ; i++) { + if (unlikely(hash == contexts_v2_options[i].hash && !strcmp(tok, contexts_v2_options[i].name))) { + ret |= contexts_v2_options[i].value; + break; + } + } + } + + return ret; +} + +inline CONTEXTS_V2_ALERT_STATUS web_client_api_request_v2_alert_status(char *o) { + CONTEXTS_V2_ALERT_STATUS 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; contexts_v2_alert_status[i].name ; i++) { + if (unlikely(hash == contexts_v2_alert_status[i].hash && !strcmp(tok, contexts_v2_alert_status[i].name))) { + ret |= contexts_v2_alert_status[i].value; + break; + } + } + } + + return ret; +} + +void web_client_api_request_v2_contexts_alerts_status_to_buffer_json_array(BUFFER *wb, const char *key, CONTEXTS_V2_ALERT_STATUS options) { + buffer_json_member_add_array(wb, key); + + RRDR_OPTIONS used = 0; // to prevent adding duplicates + for(int i = 0; contexts_v2_alert_status[i].name ; i++) { + if (unlikely((contexts_v2_alert_status[i].value & options) && !(contexts_v2_alert_status[i].value & used))) { + const char *name = contexts_v2_alert_status[i].name; + used |= contexts_v2_alert_status[i].value; + + buffer_json_add_array_item_string(wb, name); + } + } + + buffer_json_array_close(wb); +} + +void web_client_api_request_v2_contexts_options_to_buffer_json_array(BUFFER *wb, const char *key, CONTEXTS_V2_OPTIONS options) { + buffer_json_member_add_array(wb, key); + + RRDR_OPTIONS used = 0; // to prevent adding duplicates + for(int i = 0; contexts_v2_options[i].name ; i++) { + if (unlikely((contexts_v2_options[i].value & options) && !(contexts_v2_options[i].value & used))) { + const char *name = contexts_v2_options[i].name; + used |= contexts_v2_options[i].value; + + buffer_json_add_array_item_string(wb, name); + } + } + + 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) { buffer_json_member_add_array(wb, key); @@ -233,7 +340,7 @@ void web_client_api_request_v1_data_options_to_string(char *buf, size_t size, RR *write = *end = '\0'; } -inline DATASOURCE_FORMAT web_client_api_request_v1_data_format(char *name) { +inline uint32_t web_client_api_request_v1_data_format(char *name) { uint32_t hash = simple_hash(name); int i; @@ -307,7 +414,7 @@ inline int web_client_api_request_v1_alarm_count(RRDHOST *host, struct web_clien if(!name || !*name) continue; if(!value || !*value) continue; - debug(D_WEB_CLIENT, "%llu: API v1 alarm_count query param '%s' with value '%s'", w->id, name, value); + netdata_log_debug(D_WEB_CLIENT, "%llu: API v1 alarm_count query param '%s' with value '%s'", w->id, name, value); char* p = value; if(!strcmp(name, "status")) { @@ -547,7 +654,7 @@ inline int web_client_api_request_v1_chart(RRDHOST *host, struct web_client *w, // returns the HTTP code 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); + netdata_log_debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url); int ret = HTTP_RESP_BAD_REQUEST; BUFFER *dimensions = NULL; @@ -586,7 +693,7 @@ static inline int web_client_api_request_v1_data(RRDHOST *host, struct web_clien if(!name || !*name) continue; if(!value || !*value) continue; - debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value); + netdata_log_debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value); // name and value are now the parameters // they are not null and not empty @@ -732,14 +839,14 @@ static inline int web_client_api_request_v1_data(RRDHOST *host, struct web_clien 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); + netdata_log_debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName); } if(format == DATASOURCE_DATATABLE_JSONP) { if(responseHandler == NULL) responseHandler = "google.visualization.Query.setResponse"; - debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'", + netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'", w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName ); @@ -793,7 +900,7 @@ cleanup: // /api/v1/registry?action=delete&machine=${machine_guid}&name=${hostname}&url=${url}&delete_url=${delete_url} // // Search for the URLs of a machine: -// /api/v1/registry?action=search&machine=${machine_guid}&name=${hostname}&url=${url}&for=${machine_guid} +// /api/v1/registry?action=search&for=${machine_guid} // // Impersonate: // /api/v1/registry?action=switch&machine=${machine_guid}&name=${hostname}&url=${url}&to=${new_person_guid} @@ -820,16 +927,17 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * */ } - char person_guid[GUID_LEN + 1] = ""; - - debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url); + netdata_log_debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url); // TODO // The browser may send multiple cookies with our id + char person_guid[UUID_STR_LEN] = ""; char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "="); if(cookie) - strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36); + 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))) + person_guid[0] = '\0'; char action = '\0'; char *machine_guid = NULL, @@ -853,7 +961,7 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * if (!name || !*name) continue; if (!value || !*value) continue; - debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value); + netdata_log_debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value); uint32_t hash = simple_hash(name); @@ -866,7 +974,7 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * else if(vhash == hash_search && !strcmp(value, "search")) action = 'S'; else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W'; #ifdef NETDATA_INTERNAL_CHECKS - else error("unknown registry action '%s'", value); + else netdata_log_error("unknown registry action '%s'", value); #endif /* NETDATA_INTERNAL_CHECKS */ } /* @@ -896,7 +1004,7 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * to_person_guid = value; } #ifdef NETDATA_INTERNAL_CHECKS - else error("unused registry URL parameter '%s' with value '%s'", name, value); + else netdata_log_error("unused registry URL parameter '%s' with value '%s'", name, value); #endif /* NETDATA_INTERNAL_CHECKS */ } @@ -918,10 +1026,12 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * return web_client_permission_denied(w); } + buffer_no_cacheable(w->response.data); + switch(action) { case 'A': if(unlikely(!machine_guid || !machine_url || !url_name)) { - error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')", machine_guid ? machine_guid : "UNSET", machine_url ? machine_url : "UNSET", url_name ? url_name : "UNSET"); + netdata_log_error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')", machine_guid ? machine_guid : "UNSET", machine_url ? machine_url : "UNSET", url_name ? url_name : "UNSET"); buffer_flush(w->response.data); buffer_strcat(w->response.data, "Invalid registry Access request."); return HTTP_RESP_BAD_REQUEST; @@ -932,7 +1042,7 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * case 'D': if(unlikely(!machine_guid || !machine_url || !delete_url)) { - error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET"); + netdata_log_error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET"); buffer_flush(w->response.data); buffer_strcat(w->response.data, "Invalid registry Delete request."); return HTTP_RESP_BAD_REQUEST; @@ -942,19 +1052,19 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec()); case 'S': - if(unlikely(!machine_guid || !machine_url || !search_machine_guid)) { - error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET"); + if(unlikely(!search_machine_guid)) { + netdata_log_error("Invalid registry request - search requires these parameters: for ('%s')", search_machine_guid?search_machine_guid:"UNSET"); buffer_flush(w->response.data); buffer_strcat(w->response.data, "Invalid registry Search request."); return HTTP_RESP_BAD_REQUEST; } web_client_enable_tracking_required(w); - return registry_request_search_json(host, w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec()); + return registry_request_search_json(host, w, person_guid, search_machine_guid); case 'W': if(unlikely(!machine_guid || !machine_url || !to_person_guid)) { - error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET"); + netdata_log_error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET"); buffer_flush(w->response.data); buffer_strcat(w->response.data, "Invalid registry Switch request."); return HTTP_RESP_BAD_REQUEST; @@ -1129,12 +1239,7 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb) host_functions2json(host, wb); host_collectors(host, wb); -#ifdef DISABLE_CLOUD - buffer_json_member_add_boolean(wb, "cloud-enabled", false); -#else - buffer_json_member_add_boolean(wb, "cloud-enabled", - appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", true)); -#endif + buffer_json_member_add_boolean(wb, "cloud-enabled", netdata_cloud_enabled); #ifdef ENABLE_ACLK buffer_json_member_add_boolean(wb, "cloud-available", true); @@ -1160,12 +1265,12 @@ inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb) 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 +#ifdef ENABLE_RRDPUSH_COMPRESSION buffer_json_member_add_boolean(wb, "stream-compression", host->sender && stream_has_capability(host->sender, STREAM_CAP_COMPRESSION)); -#else +#else // ! ENABLE_RRDPUSH_COMPRESSION buffer_json_member_add_boolean(wb, "stream-compression", false); -#endif //ENABLE_COMPRESSION +#endif // ENABLE_RRDPUSH_COMPRESSION #ifdef ENABLE_HTTPS buffer_json_member_add_boolean(wb, "https-enabled", true); @@ -1414,12 +1519,6 @@ int web_client_api_request_v1_dbengine_stats(RRDHOST *host __maybe_unused, struc } #endif -#ifdef NETDATA_DEV_MODE -#define ACL_DEV_OPEN_ACCESS WEB_CLIENT_ACL_DASHBOARD -#else -#define ACL_DEV_OPEN_ACCESS 0 -#endif - 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 }, @@ -1429,7 +1528,7 @@ static struct web_api_command api_commands_v1[] = { { "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 }, + { "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_ACLK_WEBRTC | WEB_CLIENT_ACL_BADGE, web_client_api_request_v1_badge }, @@ -1443,21 +1542,21 @@ static struct web_api_command api_commands_v1[] = { #if defined(ENABLE_ML) { "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 }, + // { "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 }, + {"manage/health", 0, WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_ACLK_WEBRTC_DASHBOARD_WITH_BEARER, web_client_api_request_v1_mgmt_health }, { "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 }, + {"function", 0, WEB_CLIENT_ACL_ACLK_WEBRTC_DASHBOARD_WITH_BEARER | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_function }, + {"functions", 0, WEB_CLIENT_ACL_ACLK_WEBRTC_DASHBOARD_WITH_BEARER | ACL_DEV_OPEN_ACCESS, web_client_api_request_v1_functions }, { "dbengine_stats", 0, WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC, web_client_api_request_v1_dbengine_stats }, // terminator - { NULL, 0, WEB_CLIENT_ACL_NONE, NULL }, + { NULL, 0, WEB_CLIENT_ACL_NONE, NULL }, }; inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url_path_endpoint) { -- cgit v1.2.3