| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "database/rrd.h" |
| 4 | #include "registry_internals.h" |
| 5 | |
| 6 | #define REGISTRY_STATUS_OK "ok" |
| 7 | #define REGISTRY_STATUS_REDIRECT "redirect" |
| 8 | #define REGISTRY_STATUS_FAILED "failed" |
| 9 | #define REGISTRY_STATUS_DISABLED "disabled" |
| 10 | |
| 11 | bool registry_is_valid_url(const char *url) { |
| 12 | return url && (*url == 'h' || *url == '*'); |
| 13 | } |
| 14 | |
| 15 | // ---------------------------------------------------------------------------- |
| 16 | // REGISTRY concurrency locking |
| 17 | |
| 18 | static inline void registry_lock(void) { |
| 19 | netdata_mutex_lock(®istry.lock); |
| 20 | } |
| 21 | |
| 22 | static inline void registry_unlock(void) { |
| 23 | netdata_mutex_unlock(®istry.lock); |
| 24 | } |
| 25 | |
| 26 | // ---------------------------------------------------------------------------- |
| 27 | // COOKIES |
| 28 | |
| 29 | static void registry_set_cookie(struct web_client *w, const char *guid) { |
| 30 | char rfc7231_expires[RFC7231_MAX_LENGTH]; |
| 31 | rfc7231_datetime(rfc7231_expires, sizeof(rfc7231_expires), now_realtime_sec() + registry.persons_expiration); |
| 32 | |
| 33 | buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s\r\n", guid, rfc7231_expires); |
| 34 | buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; SameSite=Strict; Expires=%s\r\n", guid, rfc7231_expires); |
| 35 | if(registry.enable_cookies_samesite_secure) |
| 36 | buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; SameSite=None; Secure\r\n", guid, rfc7231_expires); |
| 37 | |
| 38 | if(registry.registry_domain && *registry.registry_domain) { |
| 39 | buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s\r\n", guid, rfc7231_expires, registry.registry_domain); |
| 40 | buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s; SameSite=Strict\r\n", guid, rfc7231_expires, registry.registry_domain); |
| 41 | if(registry.enable_cookies_samesite_secure) |
| 42 | buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s; SameSite=None; Secure\r\n", guid, rfc7231_expires, registry.registry_domain); |
| 43 | } |
| 44 | |
| 45 | w->response.has_cookies = true; |
| 46 | } |
| 47 | |
| 48 | static inline void registry_set_person_cookie(struct web_client *w, REGISTRY_PERSON *p) { |
| 49 | registry_set_cookie(w, p->guid); |
| 50 | } |
| 51 | |
| 52 | |
| 53 | // ---------------------------------------------------------------------------- |
| 54 | // JSON GENERATION |
| 55 | |
| 56 | static inline void registry_json_header(RRDHOST *host, struct web_client *w, const char *action, const char *status) { |
| 57 | buffer_flush(w->response.data); |
| 58 | w->response.data->content_type = CT_APPLICATION_JSON; |
| 59 | buffer_json_initialize(w->response.data, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT); |
| 60 | buffer_json_member_add_string(w->response.data, "action", action); |
| 61 | buffer_json_member_add_string(w->response.data, "status", status); |
| 62 | buffer_json_member_add_string(w->response.data, "hostname", rrdhost_registry_hostname(host)); |
| 63 | buffer_json_member_add_string(w->response.data, "machine_guid", host->machine_guid); |
| 64 | } |
| 65 | |
| 66 | static inline void registry_json_footer(struct web_client *w) { |
| 67 | buffer_json_finalize(w->response.data); |
| 68 | } |
| 69 | |
| 70 | static inline int registry_json_disabled(RRDHOST *host, struct web_client *w, const char *action) { |
| 71 | registry_json_header(host, w, action, REGISTRY_STATUS_DISABLED); |
| 72 | |
| 73 | buffer_json_member_add_string(w->response.data, "registry", registry.registry_to_announce); |
| 74 | |
| 75 | registry_json_footer(w); |
| 76 | return HTTP_RESP_OK; |
| 77 | } |
| 78 | |
| 79 | |
| 80 | // ---------------------------------------------------------------------------- |
| 81 | // CALLBACKS FOR WALKING THROUGH REGISTRY OBJECTS |
| 82 | |
| 83 | // structure used be the callbacks below |
| 84 | struct registry_json_walk_person_urls_callback { |
| 85 | REGISTRY_PERSON *p; |
| 86 | REGISTRY_MACHINE *m; |
| 87 | struct web_client *w; |
| 88 | int count; |
| 89 | }; |
| 90 | |
| 91 | static STRING *asterisks = NULL; |
| 92 | |
| 93 | // callback for rendering PERSON_URLs |
| 94 | static int registry_json_person_url_callback(REGISTRY_PERSON_URL *pu, struct registry_json_walk_person_urls_callback *c) { |
| 95 | if(unlikely(!asterisks)) |
| 96 | asterisks = string_strdupz("***"); |
| 97 | |
| 98 | struct web_client *w = c->w; |
| 99 | |
| 100 | if (pu->url == asterisks) return 0; |
| 101 | |
| 102 | buffer_json_add_array_item_array(w->response.data); |
| 103 | buffer_json_add_array_item_string(w->response.data, pu->machine->guid); |
| 104 | buffer_json_add_array_item_string(w->response.data, string2str(pu->url)); |
| 105 | buffer_json_add_array_item_uint64(w->response.data, pu->last_t * (uint64_t) 1000); |
| 106 | buffer_json_add_array_item_uint64(w->response.data, pu->usages); |
| 107 | buffer_json_add_array_item_string(w->response.data, string2str(pu->machine_name)); |
| 108 | buffer_json_array_close(w->response.data); |
| 109 | |
| 110 | return 1; |
| 111 | } |
| 112 | |
| 113 | // callback for rendering MACHINE_URLs |
| 114 | static int registry_json_machine_url_callback(REGISTRY_MACHINE_URL *mu, struct registry_json_walk_person_urls_callback *c, STRING *hostname) { |
| 115 | if(unlikely(!asterisks)) |
| 116 | asterisks = string_strdupz("***"); |
| 117 | |
| 118 | struct web_client *w = c->w; |
| 119 | REGISTRY_MACHINE *m = c->m; |
| 120 | |
| 121 | if (mu->url == asterisks) return 0; |
| 122 | |
| 123 | buffer_json_add_array_item_array(w->response.data); |
| 124 | buffer_json_add_array_item_string(w->response.data, m->guid); |
| 125 | buffer_json_add_array_item_string(w->response.data, string2str(mu->url)); |
| 126 | buffer_json_add_array_item_uint64(w->response.data, mu->last_t * (uint64_t) 1000); |
| 127 | buffer_json_add_array_item_uint64(w->response.data, mu->usages); |
| 128 | buffer_json_add_array_item_string(w->response.data, string2str(hostname)); |
| 129 | buffer_json_array_close(w->response.data); |
| 130 | |
| 131 | return 1; |
| 132 | } |
| 133 | |
| 134 | // ---------------------------------------------------------------------------- |
| 135 | |
| 136 | // structure used be the callbacks below |
| 137 | struct registry_person_url_callback_verify_machine_exists_data { |
| 138 | REGISTRY_MACHINE *m; |
| 139 | int count; |
| 140 | }; |
| 141 | |
| 142 | static inline int registry_person_url_callback_verify_machine_exists(REGISTRY_PERSON_URL *pu, struct registry_person_url_callback_verify_machine_exists_data *d) { |
| 143 | REGISTRY_MACHINE *m = d->m; |
| 144 | |
| 145 | if(pu->machine == m) |
| 146 | d->count++; |
| 147 | |
| 148 | return 0; |
| 149 | } |
| 150 | |
| 151 | // ---------------------------------------------------------------------------- |
| 152 | // dynamic update of the configuration |
| 153 | // The registry does not seem to be designed to support this and I cannot see any concurrency protection |
| 154 | // that could make this safe, so try to be as atomic as possible. |
| 155 | |
| 156 | void registry_update_cloud_base_url() { |
| 157 | registry.cloud_base_url = cloud_config_url_get(); |
| 158 | nd_setenv("NETDATA_REGISTRY_CLOUD_BASE_URL", registry.cloud_base_url, 1); |
| 159 | } |
| 160 | |
| 161 | // ---------------------------------------------------------------------------- |
| 162 | // public HELLO request |
| 163 | |
| 164 | int registry_request_hello_json(RRDHOST *host, struct web_client *w, bool do_not_track) { |
| 165 | registry_json_header(host, w, "hello", REGISTRY_STATUS_OK); |
| 166 | |
| 167 | if(!UUIDiszero(host->node_id)) |
| 168 | buffer_json_member_add_uuid(w->response.data, "node_id", host->node_id.uuid); |
| 169 | |
| 170 | buffer_json_member_add_object(w->response.data, "agent"); |
| 171 | { |
| 172 | buffer_json_member_add_string(w->response.data, "machine_guid", localhost->machine_guid); |
| 173 | |
| 174 | if(!UUIDiszero(localhost->node_id)) |
| 175 | buffer_json_member_add_uuid(w->response.data, "node_id", localhost->node_id.uuid); |
| 176 | |
| 177 | CLAIM_ID claim_id = rrdhost_claim_id_get(host); |
| 178 | if (claim_id_is_set(claim_id)) |
| 179 | buffer_json_member_add_string(w->response.data, "claim_id", claim_id.str); |
| 180 | |
| 181 | buffer_json_member_add_boolean(w->response.data, "bearer_protection", netdata_is_protected_by_bearer); |
| 182 | } |
| 183 | buffer_json_object_close(w->response.data); |
| 184 | |
| 185 | CLOUD_STATUS status = cloud_status(); |
| 186 | buffer_json_member_add_string(w->response.data, "cloud_status", CLOUD_STATUS_2str(status)); |
| 187 | buffer_json_member_add_string(w->response.data, "cloud_base_url", registry.cloud_base_url); |
| 188 | |
| 189 | buffer_json_member_add_string(w->response.data, "registry", registry.registry_to_announce); |
| 190 | buffer_json_member_add_boolean(w->response.data, "anonymous_statistics", do_not_track ? false : netdata_anonymous_statistics_enabled); |
| 191 | buffer_json_member_add_boolean(w->response.data, "X-Netdata-Auth", true); |
| 192 | |
| 193 | buffer_json_member_add_array(w->response.data, "nodes"); |
| 194 | RRDHOST *h; |
| 195 | dfe_start_read(rrdhost_root_index, h) { |
| 196 | buffer_json_add_array_item_object(w->response.data); |
| 197 | buffer_json_member_add_string(w->response.data, "machine_guid", h->machine_guid); |
| 198 | |
| 199 | if(!UUIDiszero(h->node_id)) |
| 200 | buffer_json_member_add_uuid(w->response.data, "node_id", h->node_id.uuid); |
| 201 | |
| 202 | buffer_json_member_add_string(w->response.data, "hostname", rrdhost_registry_hostname(h)); |
| 203 | buffer_json_object_close(w->response.data); |
| 204 | } |
| 205 | dfe_done(h); |
| 206 | buffer_json_array_close(w->response.data); // nodes |
| 207 | |
| 208 | registry_json_footer(w); |
| 209 | return HTTP_RESP_OK; |
| 210 | } |
| 211 | |
| 212 | // ---------------------------------------------------------------------------- |
| 213 | // public ACCESS request |
| 214 | |
| 215 | // the main method for registering an access |
| 216 | int registry_request_access_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) { |
| 217 | if(unlikely(!registry.enabled)) |
| 218 | return registry_json_disabled(host, w, "access"); |
| 219 | |
| 220 | if(!registry_is_valid_url(url)) { |
| 221 | buffer_flush(w->response.data); |
| 222 | buffer_strcat(w->response.data, "Invalid URL given in the request"); |
| 223 | return HTTP_RESP_BAD_REQUEST; |
| 224 | } |
| 225 | |
| 226 | // ------------------------------------------------------------------------ |
| 227 | // verify the browser supports cookies or the bearer |
| 228 | |
| 229 | if(registry.verify_cookies_redirects > 0 && !person_guid[0]) { |
| 230 | registry_lock(); |
| 231 | registry_request_access(REGISTRY_VERIFY_COOKIES_GUID, machine_guid, url, name, when); |
| 232 | registry_unlock(); |
| 233 | |
| 234 | buffer_flush(w->response.data); |
| 235 | registry_set_cookie(w, REGISTRY_VERIFY_COOKIES_GUID); |
| 236 | w->response.data->content_type = CT_APPLICATION_JSON; |
| 237 | registry_json_header(host, w, "access", REGISTRY_STATUS_REDIRECT); |
| 238 | buffer_json_member_add_string(w->response.data, "person_guid", REGISTRY_VERIFY_COOKIES_GUID); |
| 239 | buffer_json_member_add_string(w->response.data, "registry", registry.registry_to_announce); |
| 240 | registry_json_footer(w); |
| 241 | return HTTP_RESP_OK; |
| 242 | } |
| 243 | |
| 244 | if(unlikely(person_guid[0] && is_dummy_person(person_guid))) |
| 245 | // it passed the check - they gave us a different person_guid |
| 246 | // empty the dummy one, so that we will generate a new person_guid |
| 247 | person_guid[0] = '\0'; |
| 248 | |
| 249 | // ------------------------------------------------------------------------ |
| 250 | |
| 251 | registry_lock(); |
| 252 | |
| 253 | REGISTRY_PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when); |
| 254 | if(!p) { |
| 255 | registry_json_header(host, w, "access", REGISTRY_STATUS_FAILED); |
| 256 | registry_json_footer(w); |
| 257 | registry_unlock(); |
| 258 | return HTTP_RESP_INTERNAL_SERVER_ERROR; |
| 259 | } |
| 260 | |
| 261 | // set the cookie |
| 262 | registry_set_person_cookie(w, p); |
| 263 | |
| 264 | // generate the response |
| 265 | registry_json_header(host, w, "access", REGISTRY_STATUS_OK); |
| 266 | buffer_json_member_add_string(w->response.data, "person_guid", p->guid); |
| 267 | buffer_json_member_add_array(w->response.data, "urls"); |
| 268 | |
| 269 | struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 }; |
| 270 | for(REGISTRY_PERSON_URL *pu = p->person_urls; pu ;pu = pu->next) |
| 271 | registry_json_person_url_callback(pu, &c); |
| 272 | buffer_json_array_close(w->response.data); // urls |
| 273 | |
| 274 | registry_json_footer(w); |
| 275 | registry_unlock(); |
| 276 | return HTTP_RESP_OK; |
| 277 | } |
| 278 | |
| 279 | // ---------------------------------------------------------------------------- |
| 280 | // public DELETE request |
| 281 | |
| 282 | // the main method for deleting a URL from a person |
| 283 | int registry_request_delete_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) { |
| 284 | if(!registry.enabled) |
| 285 | return registry_json_disabled(host, w, "delete"); |
| 286 | |
| 287 | if(!registry_is_valid_url(url)) { |
| 288 | buffer_flush(w->response.data); |
| 289 | buffer_strcat(w->response.data, "Invalid URL given in the request"); |
| 290 | return HTTP_RESP_BAD_REQUEST; |
| 291 | } |
| 292 | |
| 293 | registry_lock(); |
| 294 | |
| 295 | REGISTRY_PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when); |
| 296 | if(!p) { |
| 297 | registry_json_header(host, w, "delete", REGISTRY_STATUS_FAILED); |
| 298 | registry_json_footer(w); |
| 299 | registry_unlock(); |
| 300 | return HTTP_RESP_BAD_REQUEST; |
| 301 | } |
| 302 | |
| 303 | // generate the response |
| 304 | registry_json_header(host, w, "delete", REGISTRY_STATUS_OK); |
| 305 | registry_json_footer(w); |
| 306 | registry_unlock(); |
| 307 | return HTTP_RESP_OK; |
| 308 | } |
| 309 | |
| 310 | // ---------------------------------------------------------------------------- |
| 311 | // public SEARCH request |
| 312 | |
| 313 | // the main method for searching the URLs of a netdata |
| 314 | int registry_request_search_json(RRDHOST *host, struct web_client *w, char *person_guid, char *request_machine) { |
| 315 | if(!registry.enabled) |
| 316 | return registry_json_disabled(host, w, "search"); |
| 317 | |
| 318 | if(!person_guid || !person_guid[0]) { |
| 319 | registry_json_header(host, w, "search", REGISTRY_STATUS_FAILED); |
| 320 | registry_json_footer(w); |
| 321 | return HTTP_RESP_BAD_REQUEST; |
| 322 | } |
| 323 | |
| 324 | registry_lock(); |
| 325 | |
| 326 | STRING *hostname = NULL; |
| 327 | REGISTRY_MACHINE *m = registry_request_machine(person_guid, request_machine, &hostname); |
| 328 | if(!m) { |
| 329 | registry_json_header(host, w, "search", REGISTRY_STATUS_FAILED); |
| 330 | registry_json_footer(w); |
| 331 | registry_unlock(); |
| 332 | string_freez(hostname); |
| 333 | return HTTP_RESP_NOT_FOUND; |
| 334 | } |
| 335 | |
| 336 | registry_json_header(host, w, "search", REGISTRY_STATUS_OK); |
| 337 | |
| 338 | buffer_json_member_add_array(w->response.data, "urls"); |
| 339 | struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 }; |
| 340 | |
| 341 | for(REGISTRY_MACHINE_URL *mu = m->machine_urls; mu ; mu = mu->next) |
| 342 | registry_json_machine_url_callback(mu, &c, hostname); |
| 343 | |
| 344 | buffer_json_array_close(w->response.data); |
| 345 | |
| 346 | registry_json_footer(w); |
| 347 | registry_unlock(); |
| 348 | string_freez(hostname); |
| 349 | return HTTP_RESP_OK; |
| 350 | } |
| 351 | |
| 352 | // ---------------------------------------------------------------------------- |
| 353 | // SWITCH REQUEST |
| 354 | |
| 355 | // the main method for switching user identity |
| 356 | int registry_request_switch_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url __maybe_unused, char *new_person_guid, time_t when __maybe_unused) { |
| 357 | if(!registry.enabled) |
| 358 | return registry_json_disabled(host, w, "switch"); |
| 359 | |
| 360 | if(!person_guid || !person_guid[0]) { |
| 361 | buffer_flush(w->response.data); |
| 362 | buffer_strcat(w->response.data, "Who are you? Person GUID is missing"); |
| 363 | return HTTP_RESP_BAD_REQUEST; |
| 364 | } |
| 365 | |
| 366 | if(!registry_is_valid_url(url)) { |
| 367 | buffer_flush(w->response.data); |
| 368 | buffer_strcat(w->response.data, "Invalid URL given in the request"); |
| 369 | return HTTP_RESP_BAD_REQUEST; |
| 370 | } |
| 371 | |
| 372 | registry_lock(); |
| 373 | |
| 374 | REGISTRY_PERSON *op = registry_person_find(person_guid); |
| 375 | if(!op) { |
| 376 | registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); |
| 377 | registry_json_footer(w); |
| 378 | registry_unlock(); |
| 379 | return 430; |
| 380 | } |
| 381 | |
| 382 | REGISTRY_PERSON *np = registry_person_find(new_person_guid); |
| 383 | if(!np) { |
| 384 | registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); |
| 385 | registry_json_footer(w); |
| 386 | registry_unlock(); |
| 387 | return 431; |
| 388 | } |
| 389 | |
| 390 | REGISTRY_MACHINE *m = registry_machine_find(machine_guid); |
| 391 | if(!m) { |
| 392 | registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); |
| 393 | registry_json_footer(w); |
| 394 | registry_unlock(); |
| 395 | return 432; |
| 396 | } |
| 397 | |
| 398 | struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 }; |
| 399 | |
| 400 | // verify the old person has access to this machine |
| 401 | for(REGISTRY_PERSON_URL *pu = op->person_urls; pu ;pu = pu->next) |
| 402 | registry_person_url_callback_verify_machine_exists(pu, &data); |
| 403 | |
| 404 | if(!data.count) { |
| 405 | registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); |
| 406 | registry_json_footer(w); |
| 407 | registry_unlock(); |
| 408 | return 433; |
| 409 | } |
| 410 | |
| 411 | // verify the new person has access to this machine |
| 412 | data.count = 0; |
| 413 | for(REGISTRY_PERSON_URL *pu = np->person_urls; pu ;pu = pu->next) |
| 414 | registry_person_url_callback_verify_machine_exists(pu, &data); |
| 415 | |
| 416 | if(!data.count) { |
| 417 | registry_json_header(host, w, "switch", REGISTRY_STATUS_FAILED); |
| 418 | registry_json_footer(w); |
| 419 | registry_unlock(); |
| 420 | return 434; |
| 421 | } |
| 422 | |
| 423 | // set the cookie of the new person |
| 424 | // the user just switched identity |
| 425 | registry_set_person_cookie(w, np); |
| 426 | |
| 427 | // generate the response |
| 428 | registry_json_header(host, w, "switch", REGISTRY_STATUS_OK); |
| 429 | buffer_json_member_add_string(w->response.data, "person_guid", np->guid); |
| 430 | registry_json_footer(w); |
| 431 | |
| 432 | registry_unlock(); |
| 433 | return HTTP_RESP_OK; |
| 434 | } |
| 435 | |
| 436 | // ---------------------------------------------------------------------------- |
| 437 | // STATISTICS |
| 438 | |
| 439 | void registry_statistics(void) { |
| 440 | if(!registry.enabled) return; |
| 441 | |
| 442 | static RRDSET *sts = NULL, *stc = NULL, *stm = NULL; |
| 443 | |
| 444 | if(unlikely(!sts)) { |
| 445 | sts = rrdset_create_localhost( |
| 446 | "netdata" |
| 447 | , "registry_sessions" |
| 448 | , NULL |
| 449 | , "registry" |
| 450 | , NULL |
| 451 | , "Netdata Registry Sessions" |
| 452 | , "sessions" |
| 453 | , "registry" |
| 454 | , "stats" |
| 455 | , 131000 |
| 456 | , localhost->rrd_update_every |
| 457 | , RRDSET_TYPE_LINE |
| 458 | ); |
| 459 | |
| 460 | rrddim_add(sts, "sessions", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 461 | } |
| 462 | |
| 463 | rrddim_set(sts, "sessions", (collected_number)registry.usages_count); |
| 464 | rrdset_done(sts); |
| 465 | |
| 466 | // ------------------------------------------------------------------------ |
| 467 | |
| 468 | if(unlikely(!stc)) { |
| 469 | stc = rrdset_create_localhost( |
| 470 | "netdata" |
| 471 | , "registry_entries" |
| 472 | , NULL |
| 473 | , "registry" |
| 474 | , NULL |
| 475 | , "Netdata Registry Entries" |
| 476 | , "entries" |
| 477 | , "registry" |
| 478 | , "stats" |
| 479 | , 131100 |
| 480 | , localhost->rrd_update_every |
| 481 | , RRDSET_TYPE_LINE |
| 482 | ); |
| 483 | |
| 484 | rrddim_add(stc, "persons", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 485 | rrddim_add(stc, "machines", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 486 | rrddim_add(stc, "persons_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 487 | rrddim_add(stc, "machines_urls", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 488 | } |
| 489 | |
| 490 | rrddim_set(stc, "persons", (collected_number)registry.persons_count); |
| 491 | rrddim_set(stc, "machines", (collected_number)registry.machines_count); |
| 492 | rrddim_set(stc, "persons_urls", (collected_number)registry.persons_urls_count); |
| 493 | rrddim_set(stc, "machines_urls", (collected_number)registry.machines_urls_count); |
| 494 | rrdset_done(stc); |
| 495 | |
| 496 | // ------------------------------------------------------------------------ |
| 497 | |
| 498 | if(unlikely(!stm)) { |
| 499 | stm = rrdset_create_localhost( |
| 500 | "netdata" |
| 501 | , "registry_mem" |
| 502 | , NULL |
| 503 | , "registry" |
| 504 | , NULL |
| 505 | , "Netdata Registry Memory" |
| 506 | , "KiB" |
| 507 | , "registry" |
| 508 | , "stats" |
| 509 | , 131300 |
| 510 | , localhost->rrd_update_every |
| 511 | , RRDSET_TYPE_STACKED |
| 512 | ); |
| 513 | |
| 514 | rrddim_add(stm, "persons", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 515 | rrddim_add(stm, "machines", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 516 | rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 517 | rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); |
| 518 | } |
| 519 | |
| 520 | struct aral_statistics *p_aral_stats = aral_get_statistics(registry.persons_aral); |
| 521 | rrddim_set(stm, "persons", (collected_number)p_aral_stats->structures.allocated_bytes + (collected_number)p_aral_stats->malloc.allocated_bytes + (collected_number)p_aral_stats->mmap.allocated_bytes); |
| 522 | |
| 523 | struct aral_statistics *m_aral_stats = aral_get_statistics(registry.machines_aral); |
| 524 | rrddim_set(stm, "machines", (collected_number)m_aral_stats->structures.allocated_bytes + (collected_number)m_aral_stats->malloc.allocated_bytes + (collected_number)m_aral_stats->mmap.allocated_bytes); |
| 525 | |
| 526 | struct aral_statistics *pu_aral_stats = aral_get_statistics(registry.person_urls_aral); |
| 527 | rrddim_set(stm, "persons_urls", (collected_number)pu_aral_stats->structures.allocated_bytes + (collected_number)pu_aral_stats->malloc.allocated_bytes + (collected_number)pu_aral_stats->mmap.allocated_bytes); |
| 528 | |
| 529 | struct aral_statistics *mu_aral_stats = aral_get_statistics(registry.machine_urls_aral); |
| 530 | rrddim_set(stm, "machines_urls", (collected_number)mu_aral_stats->structures.allocated_bytes + (collected_number)mu_aral_stats->malloc.allocated_bytes + (collected_number)mu_aral_stats->mmap.allocated_bytes); |
| 531 | |
| 532 | rrdset_done(stm); |
| 533 | } |