@cryptotaxi247 / netdata-1 / commits / 37dd25429

versioning for functions (#18902)

Costa Tsaousis committed Oct 30, 2024 at 23:55 UTC 37dd2542975b5f968f17ed31e7c4fa9b460973f8
18 files changed +91 -34
src/collectors/cgroups.plugin/sys_fs_cgroup.c
+4 -2
@@ -1405,12 +1405,14 @@ void *cgroups_main(void *ptr) {
1405 cgroup_netdev_link_init();
1406
1407 rrd_function_add_inline(localhost, NULL, "containers-vms", 10,
1408 - RRDFUNCTIONS_PRIORITY_DEFAULT / 2, RRDFUNCTIONS_CGTOP_HELP,
1408 + RRDFUNCTIONS_PRIORITY_DEFAULT / 2, RRDFUNCTIONS_VERSION_DEFAULT,
1409 + RRDFUNCTIONS_CGTOP_HELP,
1410 "top", HTTP_ACCESS_ANONYMOUS_DATA,
1411 cgroup_function_cgroup_top);
1412
1413 rrd_function_add_inline(localhost, NULL, "systemd-services", 10,
1413 - RRDFUNCTIONS_PRIORITY_DEFAULT / 3, RRDFUNCTIONS_SYSTEMD_SERVICES_HELP,
1414 + RRDFUNCTIONS_PRIORITY_DEFAULT / 3, RRDFUNCTIONS_VERSION_DEFAULT,
1415 + RRDFUNCTIONS_SYSTEMD_SERVICES_HELP,
1416 "top", HTTP_ACCESS_ANONYMOUS_DATA,
1417 cgroup_function_systemd_top);
1418
src/collectors/diskspace.plugin/plugin_diskspace.c
+2 -1
@@ -849,7 +849,8 @@ void *diskspace_main(void *ptr) {
849 worker_register_job_name(WORKER_JOB_CLEANUP, "cleanup");
850
851 rrd_function_add_inline(localhost, NULL, "mount-points", 10,
852 - RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_DISKSPACE_HELP,
852 + RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_VERSION_DEFAULT,
853 + RRDFUNCTIONS_DISKSPACE_HELP,
854 "top", HTTP_ACCESS_ANONYMOUS_DATA,
855 diskspace_function_mount_points);
856
src/collectors/proc.plugin/proc_diskstats.c
+2 -1
@@ -1403,7 +1403,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1403 SIMPLE_PATTERN_EXACT, true);
1404
1405 rrd_function_add_inline(localhost, NULL, "block-devices", 10,
1406 - RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_DISKSTATS_HELP,
1406 + RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_VERSION_DEFAULT,
1407 + RRDFUNCTIONS_DISKSTATS_HELP,
1408 "top", HTTP_ACCESS_ANONYMOUS_DATA,
1409 diskstats_function_block_devices);
1410 }
src/collectors/proc.plugin/proc_net_dev.c
+2 -1
@@ -1701,7 +1701,8 @@ void *netdev_main(void *ptr_is_null __maybe_unused)
1701 virtual_device_collect_delay_secs = 300;
1702
1703 rrd_function_add_inline(localhost, NULL, "network-interfaces", 10,
1704 - RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_NETDEV_HELP,
1704 + RRDFUNCTIONS_PRIORITY_DEFAULT, RRDFUNCTIONS_VERSION_DEFAULT,
1705 + RRDFUNCTIONS_NETDEV_HELP,
1706 "top", HTTP_ACCESS_ANONYMOUS_DATA,
1707 netdev_function_net_interfaces);
1708
src/daemon/config/dyncfg-tree.c
+2 -2
@@ -284,7 +284,7 @@ void dyncfg_host_init(RRDHOST *host) {
284 // This function needs to be async, although it is internal.
285 // The reason is that it can call by itself another function that may or may not be internal (sync).
286
287 - rrd_function_add(host, NULL, PLUGINSD_FUNCTION_CONFIG, 120,
288 - 1000, "Dynamic configuration", "config", HTTP_ACCESS_ANONYMOUS_DATA,
287 + rrd_function_add(host, NULL, PLUGINSD_FUNCTION_CONFIG, 120, 1000, DYNCFG_FUNCTIONS_VERSION,
288 + "Dynamic configuration", "config", HTTP_ACCESS_ANONYMOUS_DATA,
289 false, dyncfg_config_execute_cb, host);
290 }
src/daemon/config/dyncfg.c
+1
@@ -358,6 +358,7 @@ bool dyncfg_add_low_level(RRDHOST *host, const char *id, const char *path,
358 string2str(df->function),
359 120,
360 1000,
361 + DYNCFG_FUNCTIONS_VERSION,
362 "Dynamic configuration",
363 "config",
364 (view_access & edit_access),
src/daemon/config/dyncfg.h
+2
@@ -7,6 +7,8 @@
7 #include "database/rrd.h"
8 #include "database/rrdfunctions.h"
9
10 +#define DYNCFG_FUNCTIONS_VERSION 0
11 +
12 void dyncfg_add_streaming(BUFFER *wb);
13 bool dyncfg_available_for_rrdhost(RRDHOST *host);
14 void dyncfg_host_init(RRDHOST *host);
src/database/contexts/api_v2_contexts.c
+18 -9
@@ -52,6 +52,7 @@ struct function_v2_entry {
52 STRING *tags;
53 HTTP_ACCESS access;
54 int priority;
55 + uint32_t version;
56 };
57
58 struct context_v2_entry {
@@ -565,15 +566,16 @@ static ssize_t rrdcontext_to_json_v2_add_host(void *data, RRDHOST *host, bool qu
566
567 if(ctl->mode & CONTEXTS_V2_FUNCTIONS) {
568 struct function_v2_entry t = {
568 - .used = 1,
569 - .size = 1,
570 - .node_ids = &ctl->nodes.ni,
571 - .help = NULL,
572 - .tags = NULL,
573 - .access = HTTP_ACCESS_ALL,
574 - .priority = RRDFUNCTIONS_PRIORITY_DEFAULT,
569 + .used = 1,
570 + .size = 1,
571 + .node_ids = &ctl->nodes.ni,
572 + .help = NULL,
573 + .tags = NULL,
574 + .access = HTTP_ACCESS_ALL,
575 + .priority = RRDFUNCTIONS_PRIORITY_DEFAULT,
576 + .version = RRDFUNCTIONS_VERSION_DEFAULT,
577 };
576 - host_functions_to_dict(host, ctl->functions.dict, &t, sizeof(t), &t.help, &t.tags, &t.access, &t.priority);
578 + host_functions_to_dict(host, ctl->functions.dict, &t, sizeof(t), &t.help, &t.tags, &t.access, &t.priority, &t.version);
579 }
580
581 if(ctl->mode & CONTEXTS_V2_NODES) {
@@ -941,7 +943,13 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
943 dfe_start_read(ctl.functions.dict, t) {
944 buffer_json_add_array_item_object(wb);
945 {
944 - buffer_json_member_add_string(wb, "name", t_dfe.name);
946 + const char *name = t_dfe.name ? strstr(t_dfe.name, RRDFUNCTIONS_VERSION_SEPARATOR) : NULL;
947 + if(name)
948 + name += sizeof(RRDFUNCTIONS_VERSION_SEPARATOR) - 1;
949 + else
950 + name = t_dfe.name;
951 +
952 + buffer_json_member_add_string(wb, "name", name);
953 buffer_json_member_add_string(wb, "help", string2str(t->help));
954 buffer_json_member_add_array(wb, "ni");
955 {
@@ -952,6 +960,7 @@ int rrdcontext_to_json_v2(BUFFER *wb, struct api_v2_contexts_request *req, CONTE
960 buffer_json_member_add_string(wb, "tags", string2str(t->tags));
961 http_access2buffer_json_array(wb, "access", t->access);
962 buffer_json_member_add_uint64(wb, "priority", t->priority);
963 + buffer_json_member_add_uint64(wb, "version", t->version);
964 }
965 buffer_json_object_close(wb);
966 }
src/database/rrdfunctions-exporters.c
+15 -4
@@ -14,13 +14,14 @@ void rrd_chart_functions_expose_rrdpush(RRDSET *st, BUFFER *wb) {
14 if(t->options & RRD_FUNCTION_DYNCFG) continue;
15
16 buffer_sprintf(wb
17 - , PLUGINSD_KEYWORD_FUNCTION " \"%s\" %d \"%s\" \"%s\" "HTTP_ACCESS_FORMAT" %d\n"
17 + , PLUGINSD_KEYWORD_FUNCTION " \"%s\" %d \"%s\" \"%s\" "HTTP_ACCESS_FORMAT" %d %"PRIu32"\n"
18 , t_dfe.name
19 , t->timeout
20 , string2str(t->help)
21 , string2str(t->tags)
22 , (HTTP_ACCESS_FORMAT_CAST)t->access
23 , t->priority
24 + , t->version
25 );
26 }
27 dfe_done(t);
@@ -41,13 +42,14 @@ void rrd_global_functions_expose_rrdpush(RRDHOST *host, BUFFER *wb, bool dyncfg)
42 }
43
44 buffer_sprintf(wb
44 - , PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"%s\" %d \"%s\" \"%s\" "HTTP_ACCESS_FORMAT" %d\n"
45 + , PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"%s\" %d \"%s\" \"%s\" "HTTP_ACCESS_FORMAT" %d %"PRIu32"\n"
46 , tmp_dfe.name
47 , tmp->timeout
48 , string2str(tmp->help)
49 , string2str(tmp->tags)
50 , (HTTP_ACCESS_FORMAT_CAST)tmp->access
51 , tmp->priority
52 + , tmp->version
53 );
54 }
55 dfe_done(tmp);
@@ -66,6 +68,7 @@ static void functions2json(DICTIONARY *functions, BUFFER *wb) {
68 {
69 buffer_json_member_add_string_or_empty(wb, "help", string2str(t->help));
70 buffer_json_member_add_int64(wb, "timeout", (int64_t) t->timeout);
71 + buffer_json_member_add_uint64(wb, "version", (uint64_t) t->version);
72
73 char options[65];
74 snprintfz(
@@ -105,6 +108,7 @@ void host_functions2json(RRDHOST *host, BUFFER *wb) {
108 {
109 buffer_json_member_add_string(wb, "help", string2str(t->help));
110 buffer_json_member_add_int64(wb, "timeout", t->timeout);
111 + buffer_json_member_add_uint64(wb, "version", (uint64_t) t->version);
112 buffer_json_member_add_array(wb, "options");
113 {
114 if (t->options & RRD_FUNCTION_GLOBAL)
@@ -138,7 +142,7 @@ void chart_functions_to_dict(DICTIONARY *rrdset_functions_view, DICTIONARY *dst,
142 }
143
144 void host_functions_to_dict(RRDHOST *host, DICTIONARY *dst, void *value, size_t value_size,
141 - STRING **help, STRING **tags, HTTP_ACCESS *access, int *priority) {
145 + STRING **help, STRING **tags, HTTP_ACCESS *access, int *priority, uint32_t *version) {
146 if(!host || !host->functions || !dictionary_entries(host->functions) || !dst) return;
147
148 struct rrd_host_function *t;
@@ -158,7 +162,14 @@ void host_functions_to_dict(RRDHOST *host, DICTIONARY *dst, void *value, size_t
162 if(priority)
163 *priority = t->priority;
164
161 - dictionary_set(dst, t_dfe.name, value, value_size);
165 + if(version)
166 + *version = t->version;
167 +
168 + char key[UINT64_MAX_LENGTH + sizeof(RRDFUNCTIONS_VERSION_SEPARATOR) + strlen(t_dfe.name)];
169 + snprintfz(key, sizeof(key), "%"PRIu32 RRDFUNCTIONS_VERSION_SEPARATOR "%s",
170 + t->version, t_dfe.name);
171 +
172 + dictionary_set(dst, key, value, value_size);
173 }
174 dfe_done(t);
175 }
src/database/rrdfunctions-exporters.h
+3 -1
@@ -5,13 +5,15 @@
5
6 #include "rrd.h"
7
8 +#define RRDFUNCTIONS_VERSION_SEPARATOR "|"
9 +
10 void rrd_chart_functions_expose_rrdpush(RRDSET *st, BUFFER *wb);
11 void rrd_global_functions_expose_rrdpush(RRDHOST *host, BUFFER *wb, bool dyncfg);
12
13 void chart_functions2json(RRDSET *st, BUFFER *wb);
14 void chart_functions_to_dict(DICTIONARY *rrdset_functions_view, DICTIONARY *dst, void *value, size_t value_size);
15 void host_functions_to_dict(RRDHOST *host, DICTIONARY *dst, void *value, size_t value_size, STRING **help, STRING **tags,
14 - HTTP_ACCESS *access, int *priority);
16 + HTTP_ACCESS *access, int *priority, uint32_t *version);
17 void host_functions2json(RRDHOST *host, BUFFER *wb);
18
19 #endif //NETDATA_RRDFUNCTIONS_EXPORTERS_H
src/database/rrdfunctions-inline.c
+3 -2
@@ -30,7 +30,7 @@ static int rrd_function_run_inline(struct rrd_function_execute *rfe, void *data)
30 return code;
31 }
32
33 -void rrd_function_add_inline(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority,
33 +void rrd_function_add_inline(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority, uint32_t version,
34 const char *help, const char *tags,
35 HTTP_ACCESS access, rrd_function_execute_inline_cb_t execute_cb) {
36
@@ -39,6 +39,7 @@ void rrd_function_add_inline(RRDHOST *host, RRDSET *st, const char *name, int ti
39 struct rrd_function_inline *fi = callocz(1, sizeof(struct rrd_function_inline));
40 fi->cb = execute_cb;
41
42 - rrd_function_add(host, st, name, timeout, priority, help, tags, access, true,
42 + rrd_function_add(host, st, name, timeout, priority, version,
43 + help, tags, access, true,
44 rrd_function_run_inline, fi);
45 }
src/database/rrdfunctions-inline.h
+1 -1
@@ -7,7 +7,7 @@
7
8 typedef int (*rrd_function_execute_inline_cb_t)(BUFFER *wb, const char *function, BUFFER *payload, const char *source);
9
10 -void rrd_function_add_inline(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority,
10 +void rrd_function_add_inline(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority, uint32_t version,
11 const char *help, const char *tags,
12 HTTP_ACCESS access, rrd_function_execute_inline_cb_t execute_cb);
13
src/database/rrdfunctions-internals.h
+1
@@ -24,6 +24,7 @@ struct rrd_host_function {
24 STRING *tags;
25 int timeout; // the default timeout of the function
26 int priority;
27 + uint32_t version;
28
29 rrd_function_execute_cb_t execute_cb;
30 void *execute_cb_data;
src/database/rrdfunctions.c
+16 -4
@@ -94,13 +94,24 @@ static bool rrd_functions_conflict_callback(const DICTIONARY_ITEM *item __maybe_
94
95 if(rdcf->timeout != new_rdcf->timeout) {
96 nd_log(NDLS_DAEMON, NDLP_DEBUG,
97 - "FUNCTIONS: function '%s' of host '%s' changed timeout",
98 - dictionary_acquired_item_name(item), rrdhost_hostname(host));
97 + "FUNCTIONS: function '%s' of host '%s' changed timeout (from %d to %d)",
98 + dictionary_acquired_item_name(item), rrdhost_hostname(host),
99 + rdcf->timeout, new_rdcf->timeout);
100
101 rdcf->timeout = new_rdcf->timeout;
102 changed = true;
103 }
104
105 + if(rdcf->version != new_rdcf->version) {
106 + nd_log(NDLS_DAEMON, NDLP_DEBUG,
107 + "FUNCTIONS: function '%s' of host '%s' changed version (from %"PRIu32", to %"PRIu32")",
108 + dictionary_acquired_item_name(item), rrdhost_hostname(host),
109 + rdcf->version, new_rdcf->version);
110 +
111 + rdcf->version = new_rdcf->version;
112 + changed = true;
113 + }
114 +
115 if(rdcf->priority != new_rdcf->priority) {
116 nd_log(NDLS_DAEMON, NDLP_DEBUG,
117 "FUNCTIONS: function '%s' of host '%s' changed priority",
@@ -188,7 +199,7 @@ static inline RRD_FUNCTION_OPTIONS get_function_options(RRDSET *st, const char *
199 return options | (is_function_restricted(name, tags) ? RRD_FUNCTION_RESTRICTED : 0);
200 }
201
191 -void rrd_function_add(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority,
202 +void rrd_function_add(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority, uint32_t version,
203 const char *help, const char *tags,
204 HTTP_ACCESS access, bool sync,
205 rrd_function_execute_cb_t execute_cb, void *execute_cb_data) {
@@ -212,13 +223,14 @@ void rrd_function_add(RRDHOST *host, RRDSET *st, const char *name, int timeout,
223 struct rrd_host_function tmp = {
224 .sync = sync,
225 .timeout = timeout,
226 + .version = version,
227 + .priority = priority,
228 .options = get_function_options(st, name, tags),
229 .access = access,
230 .execute_cb = execute_cb,
231 .execute_cb_data = execute_cb_data,
232 .help = string_strdupz(help),
233 .tags = string_strdupz(tags),
221 - .priority = priority,
234 };
235 const DICTIONARY_ITEM *item = dictionary_set_and_acquire_item(host->functions, key, &tmp, sizeof(tmp));
236
src/database/rrdfunctions.h
+2 -1
@@ -7,6 +7,7 @@
7 #include "libnetdata/libnetdata.h"
8
9 #define RRDFUNCTIONS_PRIORITY_DEFAULT 100
10 +#define RRDFUNCTIONS_VERSION_DEFAULT 0
11 #define RRDFUNCTIONS_TAG_HIDDEN "hidden"
12
13 #define RRDFUNCTIONS_TIMEOUT_EXTENSION_UT (1 * USEC_PER_SEC)
@@ -67,7 +68,7 @@ void rrd_functions_host_init(RRDHOST *host);
68 void rrd_functions_host_destroy(RRDHOST *host);
69
70 // add a function, to be run from the collector
70 -void rrd_function_add(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority, const char *help, const char *tags,
71 +void rrd_function_add(RRDHOST *host, RRDSET *st, const char *name, int timeout, int priority, uint32_t version, const char *help, const char *tags,
72 HTTP_ACCESS access, bool sync, rrd_function_execute_cb_t execute_cb,
73 void *execute_cb_data);
74
src/plugins.d/README.md
+4 -2
@@ -461,13 +461,15 @@ The `source` is an integer field that can have the following values:
461
462 The plugin can register functions to Netdata, like this:
463
464 -> FUNCTION [GLOBAL] "name and parameters of the function" timeout "help string for users" "tags" "access"
464 +> FUNCTION [GLOBAL] "name and parameters of the function" timeout "help string for users" "tags" "access" priority version
465
466 - Tags currently recognized are either `top` or `logs` (or both, space separated).
467 - Access is one of `any`, `member`, or `admin`:
468 - `any` to offer the function to all users of Netdata, even if they are not authenticated.
469 - `member` to offer the function to all authenticated members of Netdata.
470 - - `admin` to offer the function only to authenticated administrators.
470 + - `admin` to offer the function only to authenticated administrators.
471 +- Priority defines the position of the function relative to the other functions (default is 100).
472 +- Version defines the version of the function (default is 0).
473
474 Users can use a function to ask for more information from the collector. Netdata maintains a registry of functions in 2 levels:
475
src/plugins.d/pluginsd_functions.c
+10 -3
@@ -285,6 +285,7 @@ PARSER_RC pluginsd_function(char **words, size_t num_words, PARSER *parser) {
285 char *tags = get_word(words, num_words, i++);
286 char *access_str = get_word(words, num_words, i++);
287 char *priority_str = get_word(words, num_words, i++);
288 + char *version_str = get_word(words, num_words, i++);
289
290 RRDHOST *host = pluginsd_require_scope_host(parser, PLUGINSD_KEYWORD_FUNCTION);
291 if(!host) return PARSER_RC_ERROR;
@@ -293,12 +294,14 @@ PARSER_RC pluginsd_function(char **words, size_t num_words, PARSER *parser) {
294 if(!st) global = true;
295
296 if (unlikely(!timeout_str || !name || !help || (!global && !st))) {
296 - netdata_log_error("PLUGINSD: 'host:%s/chart:%s' got a FUNCTION, without providing the required data (global = '%s', name = '%s', timeout = '%s', help = '%s'). Ignoring it.",
297 + netdata_log_error("PLUGINSD: 'host:%s/chart:%s' got a FUNCTION, without providing the required data (global = '%s', name = '%s', timeout = '%s', priority = '%s', version = '%s', help = '%s'). Ignoring it.",
298 rrdhost_hostname(host),
299 st?rrdset_id(st):"(unset)",
300 global?"yes":"no",
301 name?name:"(unset)",
301 - timeout_str ? timeout_str : "(unset)",
302 + timeout_str ? timeout_str : "(unset)",
303 + priority_str ? priority_str : "(unset)",
304 + version_str ? version_str : "(unset)",
305 help?help:"(unset)"
306 );
307 return PARSER_RC_ERROR;
@@ -318,7 +321,11 @@ PARSER_RC pluginsd_function(char **words, size_t num_words, PARSER *parser) {
321 priority = RRDFUNCTIONS_PRIORITY_DEFAULT;
322 }
323
321 - rrd_function_add(host, st, name, timeout_s, priority, help, tags,
324 + uint32_t version = RRDFUNCTIONS_VERSION_DEFAULT;
325 + if(version_str && *version_str)
326 + version = str2u(version_str);
327 +
328 + rrd_function_add(host, st, name, timeout_s, priority, version, help, tags,
329 http_access_from_hex_mapping_old_roles(access_str), false,
330 pluginsd_function_execute_cb, parser);
331
src/web/api/functions/functions.c
+3
@@ -11,6 +11,7 @@ void global_functions_add(void) {
11 "streaming",
12 10,
13 RRDFUNCTIONS_PRIORITY_DEFAULT + 1,
14 + RRDFUNCTIONS_VERSION_DEFAULT,
15 RRDFUNCTIONS_STREAMING_HELP,
16 "top",
17 HTTP_ACCESS_SIGNED_ID | HTTP_ACCESS_SAME_SPACE | HTTP_ACCESS_SENSITIVE_DATA,
@@ -22,6 +23,7 @@ void global_functions_add(void) {
23 "netdata-api-calls",
24 10,
25 RRDFUNCTIONS_PRIORITY_DEFAULT + 2,
26 + RRDFUNCTIONS_VERSION_DEFAULT,
27 RRDFUNCTIONS_PROGRESS_HELP,
28 "top",
29 HTTP_ACCESS_SIGNED_ID | HTTP_ACCESS_SAME_SPACE | HTTP_ACCESS_SENSITIVE_DATA,
@@ -33,6 +35,7 @@ void global_functions_add(void) {
35 RRDFUNCTIONS_BEARER_GET_TOKEN,
36 10,
37 RRDFUNCTIONS_PRIORITY_DEFAULT + 3,
38 + RRDFUNCTIONS_VERSION_DEFAULT,
39 RRDFUNCTIONS_BEARER_GET_TOKEN_HELP,
40 RRDFUNCTIONS_TAG_HIDDEN,
41 HTTP_ACCESS_SIGNED_ID | HTTP_ACCESS_SAME_SPACE | HTTP_ACCESS_SENSITIVE_DATA,