summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCosta Tsaousis <costa@netdata.cloud>2024-02-25 03:36:39 +0200
committerGitHub <noreply@github.com>2024-02-25 01:36:39 +0000
commitbc3ff3fabefda86d04a327987077cf2c799ecaf2 (patch)
treec894f06a19ee72d31f32a49a6f176e10599c6cdd
parent751e80476f9269b2ed0d691a6640faac156c3089 (diff)
DYNCFG: call the interceptor when a test is made on a new job (#17052)
* call the interceptor when a test is made on a new job * unify exception handling * dont shadow variable * the config tree function, that is also the catch all for all config commands, is now marked async, to allow calling async functions
-rw-r--r--src/daemon/config/dyncfg-intercept.c2
-rw-r--r--src/daemon/config/dyncfg-internals.h2
-rw-r--r--src/daemon/config/dyncfg-tree.c46
3 files changed, 41 insertions, 9 deletions
diff --git a/src/daemon/config/dyncfg-intercept.c b/src/daemon/config/dyncfg-intercept.c
index dd7052e728..812059f6fc 100644
--- a/src/daemon/config/dyncfg-intercept.c
+++ b/src/daemon/config/dyncfg-intercept.c
@@ -180,7 +180,7 @@ static int dyncfg_intercept_early_error(struct rrd_function_execute *rfe, int rc
return rc;
}
-static const DICTIONARY_ITEM *dyncfg_get_template_of_new_job(const char *job_id) {
+const DICTIONARY_ITEM *dyncfg_get_template_of_new_job(const char *job_id) {
char id_copy[strlen(job_id) + 1];
memcpy(id_copy, job_id, sizeof(id_copy));
diff --git a/src/daemon/config/dyncfg-internals.h b/src/daemon/config/dyncfg-internals.h
index df9af6fd52..181d2328fc 100644
--- a/src/daemon/config/dyncfg-internals.h
+++ b/src/daemon/config/dyncfg-internals.h
@@ -76,6 +76,8 @@ const DICTIONARY_ITEM *dyncfg_add_internal(RRDHOST *host, const char *id, const
int dyncfg_function_intercept_cb(struct rrd_function_execute *rfe, void *data);
void dyncfg_cleanup(DYNCFG *v);
+const DICTIONARY_ITEM *dyncfg_get_template_of_new_job(const char *job_id);
+
bool dyncfg_is_user_disabled(const char *id);
RRDHOST *dyncfg_rrdhost_by_uuid(UUID *uuid);
diff --git a/src/daemon/config/dyncfg-tree.c b/src/daemon/config/dyncfg-tree.c
index 0983a9ee1f..6af384daa2 100644
--- a/src/daemon/config/dyncfg-tree.c
+++ b/src/daemon/config/dyncfg-tree.c
@@ -204,31 +204,57 @@ static int dyncfg_config_execute_cb(struct rrd_function_execute *rfe, void *data
action = path;
path = NULL;
- if(id && *id && dyncfg_cmds2id(action) == DYNCFG_CMD_REMOVE) {
- const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(dyncfg_globals.nodes, id);
- if(item) {
- DYNCFG *df = dictionary_acquired_item_value(item);
+ DYNCFG_CMDS cmd = dyncfg_cmds2id(action);
+ const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(dyncfg_globals.nodes, id);
+ if(!item)
+ item = dyncfg_get_template_of_new_job(id);
- if(!rrd_function_available(host, string2str(df->function)))
- df->current.status = DYNCFG_STATUS_ORPHAN;
+ if(item) {
+ DYNCFG *df = dictionary_acquired_item_value(item);
+ if(!rrd_function_available(host, string2str(df->function)))
+ df->current.status = DYNCFG_STATUS_ORPHAN;
+
+ if(cmd == DYNCFG_CMD_REMOVE) {
bool delete = (df->current.status == DYNCFG_STATUS_ORPHAN);
dictionary_acquired_item_release(dyncfg_globals.nodes, item);
+ item = NULL;
if(delete) {
+ if(!http_access_user_has_enough_access_level_for_endpoint(rfe->user_access, df->edit_access)) {
+ code = dyncfg_default_response(
+ rfe->result.wb, HTTP_RESP_FORBIDDEN,
+ "dyncfg: you don't have enough edit permissions to execute this command");
+ goto cleanup;
+ }
+
dictionary_del(dyncfg_globals.nodes, id);
dyncfg_file_delete(id);
code = dyncfg_default_response(rfe->result.wb, 200, "");
goto cleanup;
}
}
+ else if(cmd == DYNCFG_CMD_TEST && df->type == DYNCFG_TYPE_TEMPLATE && df->current.status != DYNCFG_STATUS_ORPHAN) {
+ const char *old_rfe_function = rfe->function;
+ char buf2[2048];
+ snprintfz(buf2, sizeof(buf2), "config %s %s", dictionary_acquired_item_name(item), action);
+ rfe->function = buf2;
+ dictionary_acquired_item_release(dyncfg_globals.nodes, item);
+ item = NULL;
+ code = dyncfg_function_intercept_cb(rfe, data);
+ rfe->function = old_rfe_function;
+ return code;
+ }
+
+ if(item)
+ dictionary_acquired_item_release(dyncfg_globals.nodes, item);
}
code = HTTP_RESP_NOT_FOUND;
nd_log(NDLS_DAEMON, NDLP_ERR,
"DYNCFG: unknown config id '%s' in call: '%s'. "
"This can happen if the plugin that registered the dynamic configuration is not running now.",
- action, rfe->function);
+ id, rfe->function);
rrd_call_function_error(
rfe->result.wb,
@@ -248,7 +274,11 @@ cleanup:
// for which there is no id overloaded.
void dyncfg_host_init(RRDHOST *host) {
+ // IMPORTANT:
+ // This function needs to be async, although it is internal.
+ // The reason is that it can call by itself another function that may or may not be internal (sync).
+
rrd_function_add(host, NULL, PLUGINSD_FUNCTION_CONFIG, 120,
1000, "Dynamic configuration", "config", HTTP_ACCESS_ANONYMOUS_DATA,
- true, dyncfg_config_execute_cb, host);
+ false, dyncfg_config_execute_cb, host);
}