From b88cb93a01f31f7ff69f81b1e1eae682c1ec53e1 Mon Sep 17 00:00:00 2001 From: Costa Tsaousis Date: Thu, 12 May 2016 03:38:53 +0300 Subject: [PATCH] registry almost operational - missing delete --- src/registry.c | 45 +++++++----- src/registry.h | 2 +- src/web_client.c | 86 +++++++++++----------- web/dashboard.js | 135 ++++++++++++++++++++++++++++------- web/index.html | 182 ++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 337 insertions(+), 113 deletions(-) diff --git a/src/registry.c b/src/registry.c index 7063e85e..eeaa7c57 100644 --- a/src/registry.c +++ b/src/registry.c @@ -1011,7 +1011,9 @@ MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *u // ---------------------------------------------------------------------------- // REGISTRY JSON generation -#ifndef REGISTRY_STANDALONE_TESTS +#define REGISTRY_STATUS_OK "ok" +#define REGISTRY_STATUS_FAILED "failed" +#define REGISTRY_STATUS_DISABLED "disabled" static inline void registry_set_person_cookie(struct web_client *w, PERSON *p) { char edate[100]; @@ -1027,20 +1029,29 @@ static inline void registry_set_person_cookie(struct web_client *w, PERSON *p) { w->cookie[COOKIE_MAX] = '\0'; } - -static inline void registry_json_header(struct web_client *w, int status) { +static inline void registry_json_header(struct web_client *w, const char *action, const char *status) { w->response.data->contenttype = CT_APPLICATION_JSON; buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "{\n\t\"success\": %s,\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"", - status?"true":"false", registry.hostname, registry.machine_guid); + buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"", + action, status, registry.hostname, registry.machine_guid); } static inline void registry_json_footer(struct web_client *w) { buffer_strcat(w->response.data, "\n}\n"); } -int registry_json_redirect(struct web_client *w) { - registry_json_header(w, 0); +int registry_request_hello_json(struct web_client *w) { + registry_json_header(w, "hello", REGISTRY_STATUS_OK); + + buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"", + registry.registry_to_announce); + + registry_json_footer(w); + return 200; +} + +static inline int registry_json_disabled(struct web_client *w, const char *action) { + registry_json_header(w, action, REGISTRY_STATUS_DISABLED); buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"", registry.registry_to_announce); @@ -1092,11 +1103,11 @@ static inline int registry_json_machine_url_callback(void *entry, void *data) { // the main method for registering an access int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) { if(!registry.enabled) - return registry_json_redirect(w); + return registry_json_disabled(w, "access"); PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when); if(!p) { - registry_json_header(w, 0); + registry_json_header(w, "access", REGISTRY_STATUS_FAILED); registry_json_footer(w); return 400; } @@ -1105,7 +1116,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char * registry_set_person_cookie(w, p); // generate the response - registry_json_header(w, 1); + registry_json_header(w, "access", REGISTRY_STATUS_OK); buffer_strcat(w->response.data, ",\n\t\"urls\": ["); struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 }; @@ -1119,17 +1130,17 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char * // the main method for deleting a URL from a person int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) { if(!registry.enabled) - return registry_json_redirect(w); + return registry_json_disabled(w, "delete"); PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when); if(!p) { - registry_json_header(w, 0); + registry_json_header(w, "delete", REGISTRY_STATUS_FAILED); registry_json_footer(w); return 400; } // generate the response - registry_json_header(w, 1); + registry_json_header(w, "delete", REGISTRY_STATUS_OK); registry_json_footer(w); return 200; } @@ -1137,16 +1148,16 @@ int registry_request_delete_json(struct web_client *w, char *person_guid, char * // the main method for searching the URLs of a netdata int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) { if(!registry.enabled) - return registry_json_redirect(w); + return registry_json_disabled(w, "search"); MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when); if(!m) { - registry_json_header(w, 0); + registry_json_header(w, "search", REGISTRY_STATUS_FAILED); registry_json_footer(w); return 400; } - registry_json_header(w, 1); + registry_json_header(w, "search", REGISTRY_STATUS_OK); buffer_strcat(w->response.data, ",\n\t\"urls\": ["); struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 }; @@ -1157,8 +1168,6 @@ int registry_request_search_json(struct web_client *w, char *person_guid, char * return 200; } -#endif /* ! REGISTRY_STANDALONE_TESTS */ - // ---------------------------------------------------------------------------- // REGISTRY THIS MACHINE UNIQUE ID diff --git a/src/registry.h b/src/registry.h index 097ab4d8..03ffbb31 100644 --- a/src/registry.h +++ b/src/registry.h @@ -8,7 +8,7 @@ extern int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when); extern int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when); extern int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when); -extern int registry_json_redirect(struct web_client *w); +extern int registry_request_hello_json(struct web_client *w); extern int registry_init(void); extern void registry_free(void); diff --git a/src/web_client.c b/src/web_client.c index 581f7490..463d0862 100644 --- a/src/web_client.c +++ b/src/web_client.c @@ -889,7 +889,7 @@ int web_client_api_request_v1_registry(struct web_client *w, char *url) return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, time(NULL)); case 'H': - return registry_json_redirect(w); + return registry_request_hello_json(w); default: buffer_flush(w->response.data); @@ -1223,7 +1223,7 @@ static inline char *http_header_parse(struct web_client *w, char *s) { if(web_enable_gzip && !strcasestr(v, "gzip")) w->enable_gzip = 1; } -#endif // NETDATA_WITH_ZLIB +#endif /* NETDATA_WITH_ZLIB */ *e = ':'; *ve = '\r'; @@ -1369,30 +1369,24 @@ void web_client_process(struct web_client *w) { // the client is requesting api access code = web_client_api_request(w, url); } -#ifdef NETDATA_INTERNAL_CHECKS - else if(strcmp(tok, "exit") == 0) { + else if(strcmp(tok, "netdata.conf") == 0) { code = 200; + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id); + w->response.data->contenttype = CT_TEXT_PLAIN; buffer_flush(w->response.data); - - if(!netdata_exit) - buffer_strcat(w->response.data, "ok, will do..."); - else - buffer_strcat(w->response.data, "I am doing it already"); - - netdata_exit = 1; + generate_config(w->response.data, 0); } -#endif else if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data" - // the client is requesting rrd data + // the client is requesting rrd data -- OLD API code = web_client_data_request(w, url, DATASOURCE_JSON); } else if(strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource" - // the client is requesting google datasource + // the client is requesting google datasource -- OLD API code = web_client_data_request(w, url, DATASOURCE_DATATABLE_JSONP); } else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph" - // the client is requesting an rrd graph + // the client is requesting an rrd graph -- OLD API // get the name of the data to show tok = mystrsep(&url, "/?&"); @@ -1422,7 +1416,40 @@ void web_client_process(struct web_client *w) { buffer_strcat(w->response.data, "Graph name?\r\n"); } } + else if(strcmp(tok, "list") == 0) { + // OLD API + code = 200; + + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id); + + buffer_flush(w->response.data); + RRDSET *st = rrdset_root; + + for ( ; st ; st = st->next ) + buffer_sprintf(w->response.data, "%s\n", st->name); + } + else if(strcmp(tok, "all.json") == 0) { + // OLD API + code = 200; + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id); + + w->response.data->contenttype = CT_APPLICATION_JSON; + buffer_flush(w->response.data); + rrd_stats_all_json(w->response.data); + } #ifdef NETDATA_INTERNAL_CHECKS + else if(strcmp(tok, "exit") == 0) { + code = 200; + w->response.data->contenttype = CT_TEXT_PLAIN; + buffer_flush(w->response.data); + + if(!netdata_exit) + buffer_strcat(w->response.data, "ok, will do..."); + else + buffer_strcat(w->response.data, "I am doing it already"); + + netdata_exit = 1; + } else if(strcmp(tok, "debug") == 0) { buffer_flush(w->response.data); @@ -1464,34 +1491,7 @@ void web_client_process(struct web_client *w) { // just leave the buffer as is // it will be copied back to the client } -#endif - else if(strcmp(tok, "list") == 0) { - code = 200; - - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id); - - buffer_flush(w->response.data); - RRDSET *st = rrdset_root; - - for ( ; st ; st = st->next ) - buffer_sprintf(w->response.data, "%s\n", st->name); - } - else if(strcmp(tok, "all.json") == 0) { - code = 200; - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id); - - w->response.data->contenttype = CT_APPLICATION_JSON; - buffer_flush(w->response.data); - rrd_stats_all_json(w->response.data); - } - else if(strcmp(tok, "netdata.conf") == 0) { - code = 200; - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id); - - w->response.data->contenttype = CT_TEXT_PLAIN; - buffer_flush(w->response.data); - generate_config(w->response.data, 0); - } +#endif /* NETDATA_INTERNAL_CHECKS */ else { char filename[FILENAME_MAX+1]; url = filename; diff --git a/web/dashboard.js b/web/dashboard.js index f0f85bd7..d201f0f6 100644 --- a/web/dashboard.js +++ b/web/dashboard.js @@ -12,6 +12,9 @@ // var netdataNoBootstrap = true; // do not load bootstrap // var netdataDontStart = true; // do not start the thread to process the charts // var netdataErrorCallback = null; // Callback function that will be invoked upon error +// var netdataNoRegistry = true; // Don't update the registry for this access +// var netdataRegistryCallback = null; // Callback function that will be invoked with one param, +// the URLs from the registry // // You can also set the default netdata server, using the following. // When this variable is not set, we assume the page is hosted on your @@ -489,7 +492,11 @@ 403: { message: "Chart library not enabled/is failed", alert: false }, 404: { message: "Chart not found", alert: false }, 405: { message: "Cannot download charts index from server", alert: true }, - 406: { message: "Invalid charts index downloaded from server", alert: true } + 406: { message: "Invalid charts index downloaded from server", alert: true }, + 407: { message: "Cannot HELLO netdata server", alert: false }, + 408: { message: "Netdata servers sent invalid response to HELLO", alert: false }, + 409: { message: "Cannot ACCESS netdata registry", alert: false }, + 410: { message: "Netdata registry ACCESS failed", alert: false } }; NETDATA.errorLast = { code: 0, @@ -3379,6 +3386,9 @@ $('.collapse').on('shown.bs.collapse', NETDATA.onscroll); NETDATA.parseDom(NETDATA.chartRefresher); + + // Registry initialization + setTimeout(NETDATA.registry.init, 1000); }; // ---------------------------------------------------------------------------------------------------------------- @@ -5374,7 +5384,7 @@ }; // ---------------------------------------------------------------------------------------------------------------- - // Start up + // Load required JS libraries and CSS NETDATA.requiredJs = [ { @@ -5472,6 +5482,10 @@ NETDATA.loadRequiredCSS(++index); }; + + // ---------------------------------------------------------------------------------------------------------------- + // Registry of netdata hosts + NETDATA.registry = { server: null, machine_guid: null, @@ -5479,55 +5493,126 @@ urls: null, init: function() { - NETDATA.registry.hello(function() { - console.log('hello completed'); - NETDATA.registry.access(function() { - console.log('access completed'); - console.log(NETDATA.registry); - }) + if(typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry) + return; + + NETDATA.registry.hello(NETDATA.serverDefault, function(data) { + if(data) { + NETDATA.registry.server = data.registry; + NETDATA.registry.machine_guid = data.machine_guid; + NETDATA.registry.hostname = data.hostname; + + NETDATA.registry.access(10, function (person_urls) { + NETDATA.registry.parsePersonUrls(person_urls); + + }); + } }); }, - hello: function(callback) { + parsePersonUrls: function(person_urls) { + if(person_urls) { + NETDATA.registry.urls = {}; + + // sort based on the timestamp of the last access + function pu_comparator_asc(a, b) { + if (a[2] < b[2]) return -1; + if (a[2] > b[2]) return 1; + return 0; + } + + var apu = person_urls.sort(pu_comparator_asc); + var len = apu.length; + while(len--) { + if(typeof NETDATA.registry.urls[apu[len][0]] === 'undefined') { + NETDATA.registry.urls[apu[len][0]] = { + guid: apu[len][0], + url: apu[len][1], + last_t: apu[len][2], + accesses: apu[len][3], + name: apu[len][4], + alternate_urls: new Array() + }; + } + else + NETDATA.registry.urls[apu[len][0]].alternate_urls.push(apu[len][1]); + } + } + + if(typeof netdataRegistryCallback === 'function') + netdataRegistryCallback(NETDATA.registry.urls); + }, + + hello: function(host, callback) { + // send HELLO to a netdata server: + // 1. verifies the server is reachable + // 2. responds with the registry URL, the machine GUID of this netdata server and its hostname $.ajax({ - url: NETDATA.serverDefault + '/api/v1/registry?action=hello', + url: host + '/api/v1/registry?action=hello', async: true, cache: false, - xhrFields: { withCredentials: true } + xhrFields: { withCredentials: true } // required for the cookie }) .done(function(data) { - NETDATA.registry.server = data.registry; - NETDATA.registry.machine_guid = data.machine_guid; - NETDATA.registry.hostname = data.hostname; + if(typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(408, host + ' response: ' + JSON.stringify(data)); + data = null; + } if(typeof callback === 'function') - callback(); + callback(data); }) .fail(function() { - console.log('failed to hello (registry) netdata server: ' + NETDATA.serverDefault); + NETDATA.error(407, host); + + if(typeof callback === 'function') + callback(null); }); }, - access: function(callback) { + access: function(max_redirects, callback) { + // send ACCESS to a netdata registry: + // 1. it let it know we are accessing a netdata server (in the URL) + // 2. it responds with a list of netdata servers we know + // the registry identifies us using a cookie it sets the first time we access it $.ajax({ - url: NETDATA.registry.server + '/api/v1/registry?action=access&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault), + url: NETDATA.registry.server + '/api/v1/registry?action=access&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&visible_url=' + encodeURIComponent(document.location), async: true, cache: false, - xhrFields: { withCredentials: true } + xhrFields: { withCredentials: true } // required for the cookie }) .done(function(data) { - NETDATA.registry.urls = data.urls; + var redirect = null; + if(typeof data.registry === 'string') + redirect = data.registry; - if(typeof callback === 'function') - callback(); + if(typeof data.status !== 'string' || data.status !== 'ok') + data = null; + + if(data === null && redirect !== null && max_redirects > 0) { + NETDATA.registry.access(max_redirects - 1, callback); + } + else if(data === null) { + NETDATA.error(409, NETDATA.registry.server + ' response: ' + JSON.stringify(data)); + if(typeof callback === 'function') + callback(null); + } + else { + if(typeof callback === 'function') + callback(data.urls); + } }) .fail(function() { - console.log('failed to access (registry) netdata server: ' + NETDATA.registry.host); + NETDATA.error(410, NETDATA.registry.server); + if(typeof callback === 'function') + callback(null); }); } - }; + // ---------------------------------------------------------------------------------------------------------------- + // Boot it! + NETDATA.errorReset(); NETDATA.loadRequiredCSS(0); @@ -5542,8 +5627,6 @@ if(NETDATA.options.debug.main_loop === true) console.log('starting chart refresh thread'); - setTimeout(NETDATA.registry.init, 500); - NETDATA.start(); } }); diff --git a/web/index.html b/web/index.html index 90db3eeb..1ec0f68a 100644 --- a/web/index.html +++ b/web/index.html @@ -191,6 +191,37 @@ font-weight: 500; } + .dropdown-menu { + min-width: 200px; + } + .dropdown-menu.columns-2 { + margin: 0; + padding: 0; + width: 400px; + } + .dropdown-menu li a { + padding: 5px 15px; + font-weight: 300; + } + .dropdown-menu.multi-column { + overflow-x: hidden; + } + .multi-column-dropdown { + list-style: none; + padding: 0; + } + .multi-column-dropdown li a { + display: block; + clear: both; + line-height: 1.428571429; + white-space: normal; + } + .multi-column-dropdown li a:hover { + text-decoration: none; + color: #f5f5f5; + background-color: #262626; + } + /* Back to top (hidden on mobile) */ .back-to-top, .dashboard-theme-toggle { @@ -320,6 +351,7 @@ else return ret; } + var netdataTheme = getTheme('slate'); function setTheme(theme) { @@ -327,15 +359,63 @@ return saveLocalStorage('netdataTheme', theme); } + + var netdataRegistryCallback = function(urls) { + var el = ''; + var a1 = ''; + + $.each(urls, function(i, u) { + // if(u.guid === NETDATA.registry.machine_guid) + el += '
  • ' + u.name + '
  • '; + a1 += '
  • '; + }); + + el += ''; + a1 += ''; + + el += '
  • How this works?
  • '; + a1 += '
  • ' + + document.getElementById('mynetdata_servers').innerHTML = el; + document.getElementById('mynetdata_actions1').innerHTML = a1; + + document.getElementById('mynetdata_servers2').innerHTML = el; + }; + - + @@ -787,8 +863,34 @@ -