@cryptotaxi247 / netdata-1 / commits / bc3ff3fab

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

Costa Tsaousis committed Feb 25, 2024 at 03:36 UTC bc3ff3fabefda86d04a327987077cf2c799ecaf2
3 files changed +41 -9
src/daemon/config/dyncfg-intercept.c
+1 -1
@@ -180,7 +180,7 @@ static int dyncfg_intercept_early_error(struct rrd_function_execute *rfe, int rc
180 return rc;
181 }
182
183 -static const DICTIONARY_ITEM *dyncfg_get_template_of_new_job(const char *job_id) {
183 +const DICTIONARY_ITEM *dyncfg_get_template_of_new_job(const char *job_id) {
184 char id_copy[strlen(job_id) + 1];
185 memcpy(id_copy, job_id, sizeof(id_copy));
186
src/daemon/config/dyncfg-internals.h
+2
@@ -76,6 +76,8 @@ const DICTIONARY_ITEM *dyncfg_add_internal(RRDHOST *host, const char *id, const
76 int dyncfg_function_intercept_cb(struct rrd_function_execute *rfe, void *data);
77 void dyncfg_cleanup(DYNCFG *v);
78
79 +const DICTIONARY_ITEM *dyncfg_get_template_of_new_job(const char *job_id);
80 +
81 bool dyncfg_is_user_disabled(const char *id);
82
83 RRDHOST *dyncfg_rrdhost_by_uuid(UUID *uuid);
src/daemon/config/dyncfg-tree.c
+38 -8
@@ -204,31 +204,57 @@ static int dyncfg_config_execute_cb(struct rrd_function_execute *rfe, void *data
204 action = path;
205 path = NULL;
206
207 - if(id && *id && dyncfg_cmds2id(action) == DYNCFG_CMD_REMOVE) {
208 - const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(dyncfg_globals.nodes, id);
209 - if(item) {
210 - DYNCFG *df = dictionary_acquired_item_value(item);
207 + DYNCFG_CMDS cmd = dyncfg_cmds2id(action);
208 + const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(dyncfg_globals.nodes, id);
209 + if(!item)
210 + item = dyncfg_get_template_of_new_job(id);
211
212 - if(!rrd_function_available(host, string2str(df->function)))
213 - df->current.status = DYNCFG_STATUS_ORPHAN;
212 + if(item) {
213 + DYNCFG *df = dictionary_acquired_item_value(item);
214
215 + if(!rrd_function_available(host, string2str(df->function)))
216 + df->current.status = DYNCFG_STATUS_ORPHAN;
217 +
218 + if(cmd == DYNCFG_CMD_REMOVE) {
219 bool delete = (df->current.status == DYNCFG_STATUS_ORPHAN);
220 dictionary_acquired_item_release(dyncfg_globals.nodes, item);
221 + item = NULL;
222
223 if(delete) {
224 + if(!http_access_user_has_enough_access_level_for_endpoint(rfe->user_access, df->edit_access)) {
225 + code = dyncfg_default_response(
226 + rfe->result.wb, HTTP_RESP_FORBIDDEN,
227 + "dyncfg: you don't have enough edit permissions to execute this command");
228 + goto cleanup;
229 + }
230 +
231 dictionary_del(dyncfg_globals.nodes, id);
232 dyncfg_file_delete(id);
233 code = dyncfg_default_response(rfe->result.wb, 200, "");
234 goto cleanup;
235 }
236 }
237 + else if(cmd == DYNCFG_CMD_TEST && df->type == DYNCFG_TYPE_TEMPLATE && df->current.status != DYNCFG_STATUS_ORPHAN) {
238 + const char *old_rfe_function = rfe->function;
239 + char buf2[2048];
240 + snprintfz(buf2, sizeof(buf2), "config %s %s", dictionary_acquired_item_name(item), action);
241 + rfe->function = buf2;
242 + dictionary_acquired_item_release(dyncfg_globals.nodes, item);
243 + item = NULL;
244 + code = dyncfg_function_intercept_cb(rfe, data);
245 + rfe->function = old_rfe_function;
246 + return code;
247 + }
248 +
249 + if(item)
250 + dictionary_acquired_item_release(dyncfg_globals.nodes, item);
251 }
252
253 code = HTTP_RESP_NOT_FOUND;
254 nd_log(NDLS_DAEMON, NDLP_ERR,
255 "DYNCFG: unknown config id '%s' in call: '%s'. "
256 "This can happen if the plugin that registered the dynamic configuration is not running now.",
231 - action, rfe->function);
257 + id, rfe->function);
258
259 rrd_call_function_error(
260 rfe->result.wb,
@@ -248,7 +274,11 @@ cleanup:
274 // for which there is no id overloaded.
275
276 void dyncfg_host_init(RRDHOST *host) {
277 + // IMPORTANT:
278 + // This function needs to be async, although it is internal.
279 + // The reason is that it can call by itself another function that may or may not be internal (sync).
280 +
281 rrd_function_add(host, NULL, PLUGINSD_FUNCTION_CONFIG, 120,
282 1000, "Dynamic configuration", "config", HTTP_ACCESS_ANONYMOUS_DATA,
253 - true, dyncfg_config_execute_cb, host);
283 + false, dyncfg_config_execute_cb, host);
284 }