3
#include "dyn_conf.h"
4
5
#define DYN_CONF_PATH_MAX (4096)
6
-#define DYN_CONF_DIR VARLIB_DIR "/etc"
6
+#define DYN_CONF_DIR VARLIB_DIR "/dynconf"
7
8
#define DYN_CONF_JOB_SCHEMA "job_schema"
9
#define DYN_CONF_SCHEMA "schema"
11
#define DYN_CONF_JOB_LIST "jobs"
12
#define DYN_CONF_CFG_EXT ".cfg"
13
14
-DICTIONARY *plugins_dict = NULL;
14
+void job_flags_wallkthrough(dyncfg_job_flg_t flags, void (*cb)(const char *str, void *data), void *data)
15
+{
16
+ if (flags & JOB_FLG_PS_LOADED)
17
+ cb("JOB_FLG_PS_LOADED", data);
18
+ if (flags & JOB_FLG_PLUGIN_PUSHED)
19
+ cb("JOB_FLG_PLUGIN_PUSHED", data);
20
+ if (flags & JOB_FLG_STREAMING_PUSHED)
21
+ cb("JOB_FLG_STREAMING_PUSHED", data);
22
+ if (flags & JOB_FLG_USER_CREATED)
23
+ cb("JOB_FLG_USER_CREATED", data);
24
+}
25
26
struct deferred_cfg_send {
27
+ DICTIONARY *plugins_dict;
28
char *plugin_name;
29
char *module_name;
30
char *job_name;
44
freez(dcs);
45
}
46
36
-static void deferred_config_push_back(const char *plugin_name, const char *module_name, const char *job_name)
47
+static void deferred_config_push_back(DICTIONARY *plugins_dict, const char *plugin_name, const char *module_name, const char *job_name)
48
{
49
struct deferred_cfg_send *deferred = callocz(1, sizeof(struct deferred_cfg_send));
50
deferred->plugin_name = strdupz(plugin_name);
53
if (job_name != NULL)
54
deferred->job_name = strdupz(job_name);
55
}
56
+ deferred->plugins_dict = plugins_dict;
57
pthread_mutex_lock(&deferred_configs_lock);
58
if (dyncfg_shutdown) {
59
pthread_mutex_unlock(&deferred_configs_lock);
107
return 0;
108
}
109
98
-json_object *get_list_of_plugins_json()
110
+json_object *get_list_of_plugins_json(DICTIONARY *plugins_dict)
111
{
112
json_object *obj = json_object_new_array();
113
126
127
json_object *json_item = json_object_new_string(module->name);
128
json_object_object_add(json_module, "name", json_item);
117
- const char *module_type;
118
- switch (module->type) {
119
- case MOD_TYPE_SINGLE:
120
- module_type = "single";
121
- break;
122
- case MOD_TYPE_ARRAY:
123
- module_type = "job_array";
124
- break;
125
- default:
126
- module_type = "unknown";
127
- break;
128
- }
129
+ const char *module_type = module_type2str(module->type);
130
json_item = json_object_new_string(module_type);
131
json_object_object_add(json_module, "type", json_item);
132
164
}
165
}
166
166
-static int _get_list_of_jobs_json_cb(const DICTIONARY_ITEM *item, void *entry, void *data)
167
+static void _job_flags2str_cb(const char *str, void *data)
168
{
168
- UNUSED(item);
169
- json_object *obj = (json_object *)data;
170
- struct job *job = (struct job *)entry;
169
+ json_object *json_item = json_object_new_string(str);
170
+ json_object_array_add((json_object *)data, json_item);
171
+}
172
173
+json_object *job2json(struct job *job) {
174
json_object *json_job = json_object_new_object();
175
+
176
json_object *json_item = json_object_new_string(job->name);
177
json_object_object_add(json_job, "name", json_item);
178
+
179
+ json_item = json_object_new_string(job_type2str(job->type));
180
+ json_object_object_add(json_job, "type", json_item);
181
+
182
+ netdata_mutex_lock(&job->lock);
183
json_item = json_object_new_string(job_status2str(job->status));
184
+ json_object_object_add(json_job, "status", json_item);
185
+
186
+ json_item = json_object_new_int(job->state);
187
json_object_object_add(json_job, "state", json_item);
188
+
189
+ json_item = job->reason == NULL ? NULL : json_object_new_string(job->reason);
190
+ json_object_object_add(json_job, "reason", json_item);
191
+
192
int64_t last_state_update_s = job->last_state_update / USEC_PER_SEC;
193
int64_t last_state_update_us = job->last_state_update % USEC_PER_SEC;
194
198
json_item = json_object_new_int64(last_state_update_us);
199
json_object_object_add(json_job, "last_state_update_us", json_item);
200
201
+ json_item = json_object_new_array();
202
+ job_flags_wallkthrough(job->flags, _job_flags2str_cb, json_item);
203
+ json_object_object_add(json_job, "flags", json_item);
204
+
205
+ netdata_mutex_unlock(&job->lock);
206
+
207
+ return json_job;
208
+}
209
+
210
+static int _get_list_of_jobs_json_cb(const DICTIONARY_ITEM *item, void *entry, void *data)
211
+{
212
+ UNUSED(item);
213
+ json_object *obj = (json_object *)data;
214
+
215
+ json_object *json_job = job2json((struct job *)entry);
216
+
217
json_object_array_add(obj, json_job);
218
219
return 0;
237
return dictionary_get(module->jobs, job_name);
238
}
239
209
-int remove_job(struct module *module, struct job *job)
240
+void unlink_job(const char *plugin_name, const char *module_name, const char *job_name)
241
{
242
// as we are going to do unlink here we better make sure we have all to build proper path
212
- if (unlikely(job->name == NULL || module == NULL || module->name == NULL || module->plugin == NULL || module->plugin->name == NULL))
213
- return 0;
243
+ if (unlikely(job_name == NULL || module_name == NULL || plugin_name == NULL))
244
+ return;
245
+ BUFFER *buffer = buffer_create(DYN_CONF_PATH_MAX, NULL);
246
+ buffer_sprintf(buffer, DYN_CONF_DIR "/%s/%s/%s" DYN_CONF_CFG_EXT, plugin_name, module_name, job_name);
247
+ unlink(buffer_tostring(buffer));
248
+ buffer_free(buffer);
249
+}
250
+
251
+void delete_job(struct configurable_plugin *plugin, const char *module_name, const char *job_name)
252
+{
253
+ struct module *module = get_module_by_name(plugin, module_name);
254
+ if (module == NULL) {
255
+ error_report("DYNCFG module \"%s\" not found", module_name);
256
+ return;
257
+ }
258
+
259
+ struct job *job_item = get_job_by_name(module, job_name);
260
+ if (job_item == NULL) {
261
+ error_report("DYNCFG job \"%s\" not found", job_name);
262
+ return;
263
+ }
264
+
265
+ dictionary_del(module->jobs, job_name);
266
+}
267
+
268
+void delete_job_pname(DICTIONARY *plugins_dict, const char *plugin_name, const char *module_name, const char *job_name)
269
+{
270
+ const DICTIONARY_ITEM *plugin_item = dictionary_get_and_acquire_item(plugins_dict, plugin_name);
271
+ if (plugin_item == NULL) {
272
+ error_report("DYNCFG plugin \"%s\" not found", plugin_name);
273
+ return;
274
+ }
275
+ struct configurable_plugin *plugin = dictionary_acquired_item_value(plugin_item);
276
+
277
+ delete_job(plugin, module_name, job_name);
278
+
279
+ dictionary_acquired_item_release(plugins_dict, plugin_item);
280
+}
281
215
- enum set_config_result rc = module->delete_job_cb(module->job_config_cb_usr_ctx, module->name, job->name);
282
+int remove_job(struct module *module, struct job *job)
283
+{
284
+ enum set_config_result rc = module->delete_job_cb(module->job_config_cb_usr_ctx, module->plugin->name, module->name, job->name);
285
286
if (rc != SET_CONFIG_ACCEPTED) {
287
error_report("DYNCFG module \"%s\" rejected delete job for \"%s\"", module->name, job->name);
288
return 0;
289
}
221
-
222
- BUFFER *buffer = buffer_create(DYN_CONF_PATH_MAX, NULL);
223
- buffer_sprintf(buffer, DYN_CONF_DIR "/%s/%s/%s" DYN_CONF_CFG_EXT, module->plugin->name, module->name, job->name);
224
- unlink(buffer_tostring(buffer));
225
- buffer_free(buffer);
226
- return dictionary_del(module->jobs, job->name);
290
+ return 1;
291
}
292
293
struct module *get_module_by_name(struct configurable_plugin *plugin, const char *module_name)
295
return dictionary_get(plugin->modules, module_name);
296
}
297
234
-inline struct configurable_plugin *get_plugin_by_name(const char *name)
298
+inline struct configurable_plugin *get_plugin_by_name(DICTIONARY *plugins_dict, const char *name)
299
{
300
return dictionary_get(plugins_dict, name);
301
}
346
return 0;
347
}
348
349
+#ifdef NETDATA_DEV_MODE
350
+#define netdata_dev_fatal(...) fatal(__VA_ARGS__)
351
+#else
352
+#define netdata_dev_fatal(...) error_report(__VA_ARGS__)
353
+#endif
354
+
355
+void dyn_conf_store_config(const char *function, const char *payload, struct configurable_plugin *plugin) {
356
+ dyncfg_config_t config = {
357
+ .data = (char*)payload,
358
+ .data_size = strlen(payload)
359
+ };
360
+
361
+ char *fnc = strdupz(function);
362
+ // split fnc to words
363
+ char *words[DYNCFG_MAX_WORDS];
364
+ size_t words_c = quoted_strings_splitter(fnc, words, DYNCFG_MAX_WORDS, isspace_map_pluginsd);
365
+
366
+ const char *fnc_name = get_word(words, words_c, 0);
367
+ if (fnc_name == NULL) {
368
+ error_report("Function name expected \"%s\"", function);
369
+ goto CLEANUP;
370
+ }
371
+ if (strncmp(fnc_name, FUNCTION_NAME_SET_PLUGIN_CONFIG, strlen(FUNCTION_NAME_SET_PLUGIN_CONFIG)) == 0) {
372
+ store_config(plugin->name, NULL, NULL, config);
373
+ goto CLEANUP;
374
+ }
375
+
376
+ if (words_c < 2) {
377
+ error_report("Module name expected \"%s\"", function);
378
+ goto CLEANUP;
379
+ }
380
+ const char *module_name = get_word(words, words_c, 1);
381
+ if (strncmp(fnc_name, FUNCTION_NAME_SET_MODULE_CONFIG, strlen(FUNCTION_NAME_SET_MODULE_CONFIG)) == 0) {
382
+ store_config(plugin->name, module_name, NULL, config);
383
+ goto CLEANUP;
384
+ }
385
+
386
+ if (words_c < 3) {
387
+ error_report("Job name expected \"%s\"", function);
388
+ goto CLEANUP;
389
+ }
390
+ const char *job_name = get_word(words, words_c, 2);
391
+ if (strncmp(fnc_name, FUNCTION_NAME_SET_JOB_CONFIG, strlen(FUNCTION_NAME_SET_JOB_CONFIG)) == 0) {
392
+ store_config(plugin->name, module_name, job_name, config);
393
+ goto CLEANUP;
394
+ }
395
+
396
+ netdata_dev_fatal("Unknown function \"%s\"", function);
397
+
398
+CLEANUP:
399
+ freez(fnc);
400
+}
401
+
402
dyncfg_config_t load_config(const char *plugin_name, const char *module_name, const char *job_id)
403
{
404
BUFFER *filename = buffer_create(DYN_CONF_PATH_MAX, NULL);
427
428
char *set_plugin_config(struct configurable_plugin *plugin, dyncfg_config_t cfg)
429
{
313
- enum set_config_result rc = plugin->set_config_cb(plugin->cb_usr_ctx, &cfg);
430
+ enum set_config_result rc = plugin->set_config_cb(plugin->cb_usr_ctx, plugin->name, &cfg);
431
if (rc != SET_CONFIG_ACCEPTED) {
432
error_report("DYNCFG plugin \"%s\" rejected config", plugin->name);
433
return "plugin rejected config";
434
}
435
319
- if (store_config(plugin->name, NULL, NULL, cfg)) {
320
- error_report("DYNCFG could not store config for module \"%s\"", plugin->name);
321
- return "could not store config on disk";
322
- }
436
return NULL;
437
}
438
440
{
441
struct configurable_plugin *plugin = mod->plugin;
442
330
- enum set_config_result rc = mod->set_config_cb(mod->config_cb_usr_ctx, mod->name, &cfg);
443
+ enum set_config_result rc = mod->set_config_cb(mod->config_cb_usr_ctx, plugin->name, mod->name, &cfg);
444
if (rc != SET_CONFIG_ACCEPTED) {
445
error_report("DYNCFG module \"%s\" rejected config", plugin->name);
446
return "module rejected config";
447
}
448
336
- if (store_config(plugin->name, mod->name, NULL, cfg)) {
337
- error_report("DYNCFG could not store config for module \"%s\"", mod->name);
338
- return "could not store config on disk";
339
- }
340
-
449
return NULL;
450
}
451
344
-struct job *job_new()
452
+struct job *job_new(const char *job_id)
453
{
454
struct job *job = callocz(1, sizeof(struct job));
455
job->state = JOB_STATUS_UNKNOWN;
456
job->last_state_update = now_realtime_usec();
457
+ job->name = strdupz(job_id);
458
+ netdata_mutex_init(&job->lock);
459
return job;
460
}
461
352
-static int set_job_config(struct job *job, dyncfg_config_t cfg)
462
+static inline void job_del(struct job *job)
463
{
354
- struct module *mod = job->module;
355
- enum set_config_result rt = mod->set_job_config_cb(mod->job_config_cb_usr_ctx, mod->name, job->name, &cfg);
356
-
357
- if (rt != SET_CONFIG_ACCEPTED) {
358
- error_report("DYNCFG module \"%s\" rejected config for job \"%s\"", mod->name, job->name);
359
- return 1;
360
- }
361
-
362
- if (store_config(mod->plugin->name, mod->name, job->name, cfg)) {
363
- error_report("DYNCFG could not store config for module \"%s\"", mod->name);
364
- return 1;
365
- }
366
-
367
- return 0;
464
+ netdata_mutex_destroy(&job->lock);
465
+ freez(job->reason);
466
+ freez((void*)job->name);
467
+ freez(job);
468
}
469
370
-struct job *add_job(struct module *mod, const char *job_id, dyncfg_config_t cfg)
470
+void job_del_cb(const DICTIONARY_ITEM *item, void *value, void *data)
471
{
372
- struct job *job = job_new();
373
- job->name = strdupz(job_id);
374
- job->module = mod;
375
-
376
- if (set_job_config(job, cfg)) {
377
- freez(job->name);
378
- freez(job);
379
- return NULL;
380
- }
381
-
382
- dictionary_set(mod->jobs, job->name, job, sizeof(job));
383
-
384
- return job;
385
-
472
+ UNUSED(item);
473
+ UNUSED(data);
474
+ job_del((struct job *)value);
475
}
476
477
void module_del_cb(const DICTIONARY_ITEM *item, void *value, void *data)
484
freez(mod);
485
}
486
398
-
399
-const DICTIONARY_ITEM *register_plugin(struct configurable_plugin *plugin)
487
+const DICTIONARY_ITEM *register_plugin(DICTIONARY *plugins_dict, struct configurable_plugin *plugin, bool localhost)
488
{
401
- if (get_plugin_by_name(plugin->name) != NULL) {
489
+ if (get_plugin_by_name(plugins_dict, plugin->name) != NULL) {
490
error_report("DYNCFG plugin \"%s\" already registered", plugin->name);
491
return NULL;
492
}
501
plugin->modules = dictionary_create(DICT_OPTION_VALUE_LINK_DONT_CLONE);
502
dictionary_register_delete_callback(plugin->modules, module_del_cb, NULL);
503
416
- deferred_config_push_back(plugin->name, NULL, NULL);
504
+ if (localhost)
505
+ deferred_config_push_back(plugins_dict, plugin->name, NULL, NULL);
506
507
dictionary_set(plugins_dict, plugin->name, plugin, sizeof(plugin));
508
510
return dictionary_get_and_acquire_item(plugins_dict, plugin->name);
511
}
512
424
-void unregister_plugin(const DICTIONARY_ITEM *plugin)
513
+void unregister_plugin(DICTIONARY *plugins_dict, const DICTIONARY_ITEM *plugin)
514
{
515
struct configurable_plugin *plug = dictionary_acquired_item_value(plugin);
516
dictionary_acquired_item_release(plugins_dict, plugin);
517
dictionary_del(plugins_dict, plug->name);
518
}
519
431
-void job_del_cb(const DICTIONARY_ITEM *item, void *value, void *data)
432
-{
433
- UNUSED(item);
434
- UNUSED(data);
435
- struct job *job = (struct job *)value;
436
- freez(job->reason);
437
- freez(job->name);
438
- freez(job);
439
-}
440
-
441
-int register_module(struct configurable_plugin *plugin, struct module *module)
520
+int register_module(DICTIONARY *plugins_dict, struct configurable_plugin *plugin, struct module *module, bool localhost)
521
{
522
if (get_module_by_name(plugin, module->name) != NULL) {
523
error_report("DYNCFG module \"%s\" already registered", module->name);
526
527
pthread_mutex_init(&module->lock, NULL);
528
450
- deferred_config_push_back(plugin->name, module->name, NULL);
529
+ if (localhost)
530
+ deferred_config_push_back(plugins_dict, plugin->name, module->name, NULL);
531
532
module->plugin = plugin;
533
535
module->jobs = dictionary_create(DICT_OPTION_VALUE_LINK_DONT_CLONE);
536
dictionary_register_delete_callback(module->jobs, job_del_cb, NULL);
537
458
- // load all jobs from disk
459
- BUFFER *path = buffer_create(DYN_CONF_PATH_MAX, NULL);
460
- buffer_sprintf(path, "%s/%s/%s", DYN_CONF_DIR, plugin->name, module->name);
461
- DIR *dir = opendir(buffer_tostring(path));
462
- if (dir != NULL) {
463
- struct dirent *ent;
464
- while ((ent = readdir(dir)) != NULL) {
465
- if (ent->d_name[0] == '.')
466
- continue;
467
- if (ent->d_type != DT_REG)
468
- continue;
469
- size_t len = strnlen(ent->d_name, NAME_MAX);
470
- if (len <= strlen(DYN_CONF_CFG_EXT))
471
- continue;
472
- if (strcmp(ent->d_name + len - strlen(DYN_CONF_CFG_EXT), DYN_CONF_CFG_EXT) != 0)
473
- continue;
474
- ent->d_name[len - strlen(DYN_CONF_CFG_EXT)] = '\0';
475
-
476
- struct job *job = job_new();
477
- job->name = strdupz(ent->d_name);
478
- job->module = module;
479
- dictionary_set(module->jobs, job->name, job, sizeof(job));
480
-
481
- deferred_config_push_back(plugin->name, module->name, job->name);
538
+ if (localhost) {
539
+ // load all jobs from disk
540
+ BUFFER *path = buffer_create(DYN_CONF_PATH_MAX, NULL);
541
+ buffer_sprintf(path, "%s/%s/%s", DYN_CONF_DIR, plugin->name, module->name);
542
+ DIR *dir = opendir(buffer_tostring(path));
543
+ if (dir != NULL) {
544
+ struct dirent *ent;
545
+ while ((ent = readdir(dir)) != NULL) {
546
+ if (ent->d_name[0] == '.')
547
+ continue;
548
+ if (ent->d_type != DT_REG)
549
+ continue;
550
+ size_t len = strnlen(ent->d_name, NAME_MAX);
551
+ if (len <= strlen(DYN_CONF_CFG_EXT))
552
+ continue;
553
+ if (strcmp(ent->d_name + len - strlen(DYN_CONF_CFG_EXT), DYN_CONF_CFG_EXT) != 0)
554
+ continue;
555
+ ent->d_name[len - strlen(DYN_CONF_CFG_EXT)] = '\0';
556
+
557
+ struct job *job = job_new(ent->d_name);
558
+ job->module = module;
559
+ job->flags = JOB_FLG_PS_LOADED;
560
+ job->type = JOB_TYPE_USER;
561
+
562
+ dictionary_set(module->jobs, job->name, job, sizeof(job));
563
+
564
+ deferred_config_push_back(plugins_dict, plugin->name, module->name, ent->d_name);
565
+ }
566
+ closedir(dir);
567
}
483
- closedir(dir);
568
+ buffer_free(path);
569
}
485
- buffer_free(path);
570
}
571
572
dictionary_set(plugin->modules, module->name, module, sizeof(module));
574
return 0;
575
}
576
577
+int register_job(DICTIONARY *plugins_dict, const char *plugin_name, const char *module_name, const char *job_name, enum job_type job_type, dyncfg_job_flg_t flags, int ignore_existing)
578
+{
579
+ int rc = 1;
580
+ const DICTIONARY_ITEM *plugin_item = dictionary_get_and_acquire_item(plugins_dict, plugin_name);
581
+ if (plugin_item == NULL) {
582
+ error_report("plugin \"%s\" not registered", plugin_name);
583
+ return rc;
584
+ }
585
+ struct configurable_plugin *plugin = dictionary_acquired_item_value(plugin_item);
586
+ struct module *mod = get_module_by_name(plugin, module_name);
587
+ if (mod == NULL) {
588
+ error_report("module \"%s\" not registered", module_name);
589
+ goto ERR_EXIT;
590
+ }
591
+ if (mod->type != MOD_TYPE_ARRAY) {
592
+ error_report("module \"%s\" is not an array", module_name);
593
+ goto ERR_EXIT;
594
+ }
595
+ if (get_job_by_name(mod, job_name) != NULL) {
596
+ if (!ignore_existing)
597
+ error_report("job \"%s\" already registered", job_name);
598
+ goto ERR_EXIT;
599
+ }
600
+
601
+ struct job *job = job_new(job_name);
602
+ job->module = mod;
603
+ job->flags = flags;
604
+ job->type = job_type;
605
+
606
+ dictionary_set(mod->jobs, job->name, job, sizeof(job));
607
+
608
+ rc = 0;
609
+ERR_EXIT:
610
+ dictionary_acquired_item_release(plugins_dict, plugin_item);
611
+ return rc;
612
+}
613
+
614
void freez_dyncfg(void *ptr) {
615
freez(ptr);
616
}
617
497
-static void handle_dyncfg_root(struct uni_http_response *resp, int method)
618
+static void handle_dyncfg_root(DICTIONARY *plugins_dict, struct uni_http_response *resp, int method)
619
{
620
if (method != HTTP_METHOD_GET) {
621
resp->content = "method not allowed";
623
resp->status = HTTP_RESP_METHOD_NOT_ALLOWED;
624
return;
625
}
505
- json_object *obj = get_list_of_plugins_json();
626
+ json_object *obj = get_list_of_plugins_json(plugins_dict);
627
json_object *wrapper = json_object_new_object();
628
json_object_object_add(wrapper, "configurable_plugins", obj);
629
resp->content = strdupz(json_object_to_json_string_ext(wrapper, JSON_C_TO_STRING_PRETTY));
639
switch(method) {
640
case HTTP_METHOD_GET:
641
{
521
- dyncfg_config_t cfg = plugin->get_config_cb(plugin->cb_usr_ctx);
642
+ dyncfg_config_t cfg = plugin->get_config_cb(plugin->cb_usr_ctx, plugin->name);
643
resp->content = mallocz(cfg.data_size);
644
memcpy(resp->content, cfg.data, cfg.data_size);
645
resp->status = HTTP_RESP_OK;
682
683
void handle_module_root(struct uni_http_response *resp, int method, struct configurable_plugin *plugin, const char *module, void *post_payload, size_t post_payload_size)
684
{
564
- if (strncmp(module, DYN_CONF_SCHEMA, strlen(DYN_CONF_SCHEMA)) == 0) {
565
- dyncfg_config_t cfg = plugin->get_config_schema_cb(plugin->cb_usr_ctx);
685
+ if (strncmp(module, DYN_CONF_SCHEMA, sizeof(DYN_CONF_SCHEMA)) == 0) {
686
+ dyncfg_config_t cfg = plugin->get_config_schema_cb(plugin->cb_usr_ctx, plugin->name);
687
resp->content = mallocz(cfg.data_size);
688
memcpy(resp->content, cfg.data, cfg.data_size);
689
resp->status = HTTP_RESP_OK;
691
resp->content_length = cfg.data_size;
692
return;
693
}
573
- if (strncmp(module, DYN_CONF_MODULE_LIST, strlen(DYN_CONF_MODULE_LIST)) == 0) {
694
+ if (strncmp(module, DYN_CONF_MODULE_LIST, sizeof(DYN_CONF_MODULE_LIST)) == 0) {
695
if (method != HTTP_METHOD_GET) {
696
resp->content = "method not allowed (only GET)";
697
resp->content_length = strlen(resp->content);
717
return;
718
}
719
if (method == HTTP_METHOD_GET) {
599
- dyncfg_config_t cfg = mod->get_config_cb(mod->config_cb_usr_ctx, mod->name);
720
+ dyncfg_config_t cfg = mod->get_config_cb(mod->config_cb_usr_ctx, plugin->name, mod->name);
721
resp->content = mallocz(cfg.data_size);
722
memcpy(resp->content, cfg.data, cfg.data_size);
723
resp->status = HTTP_RESP_OK;
772
.data = post_payload,
773
.data_size = post_payload_size
774
};
654
- job = add_job(mod, job_id, cont);
655
- if (job == NULL) {
775
+ if (mod->set_job_config_cb(mod->job_config_cb_usr_ctx, mod->plugin->name, mod->name, job_id, &cont)) {
776
resp->content = "failed to add job";
777
resp->content_length = strlen(resp->content);
778
resp->status = HTTP_RESP_INTERNAL_SERVER_ERROR;
792
switch (method) {
793
case HTTP_METHOD_GET:
794
{
675
- dyncfg_config_t cfg = mod->get_job_config_cb(mod->job_config_cb_usr_ctx, mod->name, job->name);
795
+ dyncfg_config_t cfg = mod->get_job_config_cb(mod->job_config_cb_usr_ctx, mod->plugin->name, mod->name, job->name);
796
resp->content = mallocz(cfg.data_size);
797
memcpy(resp->content, cfg.data, cfg.data_size);
798
resp->status = HTTP_RESP_OK;
812
.data = post_payload,
813
.data_size = post_payload_size
814
};
695
- if(set_job_config(job, cont)) {
696
- resp->status = HTTP_RESP_BAD_REQUEST;
815
+ if (mod->set_job_config_cb(mod->job_config_cb_usr_ctx, mod->plugin->name, mod->name, job->name, &cont) != SET_CONFIG_ACCEPTED) {
816
+ error_report("DYNCFG module \"%s\" rejected config for job \"%s\"", mod->name, job->name);
817
resp->content = "failed to set job config";
818
resp->content_length = strlen(resp->content);
819
+ resp->status = HTTP_RESP_INTERNAL_SERVER_ERROR;
820
return;
821
}
822
resp->status = HTTP_RESP_OK;
847
848
void handle_job_root(struct uni_http_response *resp, int method, struct module *mod, const char *job_id, void *post_payload, size_t post_payload_size)
849
{
729
- if (strncmp(job_id, DYN_CONF_SCHEMA, strlen(DYN_CONF_SCHEMA)) == 0) {
730
- dyncfg_config_t cfg = mod->get_config_schema_cb(mod->config_cb_usr_ctx, mod->name);
850
+ if (strncmp(job_id, DYN_CONF_SCHEMA, sizeof(DYN_CONF_SCHEMA)) == 0) {
851
+ dyncfg_config_t cfg = mod->get_config_schema_cb(mod->config_cb_usr_ctx, mod->plugin->name, mod->name);
852
resp->content = mallocz(cfg.data_size);
853
memcpy(resp->content, cfg.data, cfg.data_size);
854
resp->status = HTTP_RESP_OK;
856
resp->content_length = cfg.data_size;
857
return;
858
}
738
- if (strncmp(job_id, DYN_CONF_JOB_SCHEMA, strlen(DYN_CONF_JOB_SCHEMA)) == 0) {
739
- dyncfg_config_t cfg = mod->get_job_config_schema_cb(mod->job_config_cb_usr_ctx, mod->name);
859
+ if (strncmp(job_id, DYN_CONF_JOB_SCHEMA, sizeof(DYN_CONF_JOB_SCHEMA)) == 0) {
860
+ dyncfg_config_t cfg = mod->get_job_config_schema_cb(mod->job_config_cb_usr_ctx, mod->plugin->name, mod->name);
861
resp->content = mallocz(cfg.data_size);
862
memcpy(resp->content, cfg.data, cfg.data_size);
863
resp->status = HTTP_RESP_OK;
865
resp->content_length = cfg.data_size;
866
return;
867
}
747
- if (strncmp(job_id, DYN_CONF_JOB_LIST, strlen(DYN_CONF_JOB_LIST)) == 0) {
868
+ if (strncmp(job_id, DYN_CONF_JOB_LIST, sizeof(DYN_CONF_JOB_LIST)) == 0) {
869
if (mod->type != MOD_TYPE_ARRAY) {
870
resp->content = "module type is not job_array (can't get the list of jobs)";
871
resp->content_length = strlen(resp->content);
897
dictionary_acquired_item_release(mod->jobs, job_item);
898
}
899
779
-struct uni_http_response dyn_conf_process_http_request(int method, const char *plugin, const char *module, const char *job_id, void *post_payload, size_t post_payload_size)
900
+struct uni_http_response dyn_conf_process_http_request(DICTIONARY *plugins_dict, int method, const char *plugin, const char *module, const char *job_id, void *post_payload, size_t post_payload_size)
901
{
902
struct uni_http_response resp = {
903
.status = HTTP_RESP_INTERNAL_SERVER_ERROR,
906
.content_free = NULL,
907
.content_length = 0
908
};
909
+#ifndef NETDATA_TEST_DYNCFG
910
+ resp.content = "DYNCFG is disabled (as it is for now developer only feature). This will be enabled by default when ready for technical preview.";
911
+ resp.content_length = strlen(resp.content);
912
+ resp.status = HTTP_RESP_PRECOND_FAIL;
913
+ return resp;
914
+#endif
915
if (plugin == NULL) {
789
- handle_dyncfg_root(&resp, method);
916
+ handle_dyncfg_root(plugins_dict, &resp, method);
917
return resp;
918
}
919
const DICTIONARY_ITEM *plugin_item = dictionary_get_and_acquire_item(plugins_dict, plugin);
941
goto EXIT_PLUGIN;
942
}
943
if (mod->type != MOD_TYPE_ARRAY) {
817
- resp.content = "module is not array";
944
+ resp.content = "400 - this module is not array type";
945
resp.content_length = strlen(resp.content);
819
- resp.status = HTTP_RESP_NOT_FOUND;
946
+ resp.status = HTTP_RESP_BAD_REQUEST;
947
goto EXIT_PLUGIN;
948
}
949
handle_job_root(&resp, method, mod, job_id, post_payload, post_payload_size);
963
freez(plugin);
964
}
965
839
-void report_job_status(struct configurable_plugin *plugin, const char *module_name, const char *job_name, enum job_status status, int status_code, char *reason)
966
+// on failure - return NULL - all unlocked, nothing acquired
967
+// on success - return pointer to job item - keep job and plugin acquired and locked!!!
968
+// for caller convenience (to prevent another lock and races)
969
+// caller is responsible to unlock the job and release it when not needed anymore
970
+// this also avoids dependency creep
971
+const DICTIONARY_ITEM *report_job_status_acq_lock(DICTIONARY *plugins_dict, const DICTIONARY_ITEM **plugin_acq_item, DICTIONARY **job_dict, const char *plugin_name, const char *module_name, const char *job_name, enum job_status status, int status_code, char *reason)
972
{
841
- struct job *job = NULL;
842
- const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(plugins_dict, plugin->name);
843
- if (item == NULL) {
844
- netdata_log_error("plugin %s not found", plugin->name);
845
- freez(reason);
846
- return;
973
+ *plugin_acq_item = dictionary_get_and_acquire_item(plugins_dict, plugin_name);
974
+ if (*plugin_acq_item == NULL) {
975
+ netdata_log_error("plugin %s not found", plugin_name);
976
+ return NULL;
977
}
848
- struct configurable_plugin *plug = dictionary_acquired_item_value(item);
978
+
979
+ struct configurable_plugin *plug = dictionary_acquired_item_value(*plugin_acq_item);
980
struct module *mod = get_module_by_name(plug, module_name);
981
if (mod == NULL) {
982
netdata_log_error("module %s not found", module_name);
852
- goto EXIT_PLUGIN;
983
+ dictionary_acquired_item_release(plugins_dict, *plugin_acq_item);
984
+ return NULL;
985
}
986
if (mod->type != MOD_TYPE_ARRAY) {
987
netdata_log_error("module %s is not array", module_name);
856
- goto EXIT_PLUGIN;
988
+ dictionary_acquired_item_release(plugins_dict, *plugin_acq_item);
989
+ return NULL;
990
}
991
+ *job_dict = mod->jobs;
992
const DICTIONARY_ITEM *job_item = dictionary_get_and_acquire_item(mod->jobs, job_name);
993
if (job_item == NULL) {
994
netdata_log_error("job %s not found", job_name);
861
- goto EXIT_PLUGIN;
995
+ dictionary_acquired_item_release(plugins_dict, *plugin_acq_item);
996
+ return NULL;
997
}
863
- job = dictionary_acquired_item_value(job_item);
998
+ struct job *job = dictionary_acquired_item_value(job_item);
999
+
1000
+ pthread_mutex_lock(&job->lock);
1001
job->status = status;
1002
job->state = status_code;
1003
if (job->reason != NULL) {
1004
freez(job->reason);
1005
}
869
- job->reason = reason;
1006
+ job->reason = reason != NULL ? strdupz(reason) : NULL; // reason is optional
1007
job->last_state_update = now_realtime_usec();
1008
872
- dictionary_acquired_item_release(mod->jobs, job_item);
1009
+ job->dirty = true;
1010
874
-EXIT_PLUGIN:
875
- if (!job)
876
- freez(reason);
877
- dictionary_acquired_item_release(plugins_dict, item);
1011
+ // no unlock and acquired_item_release on success on purpose
1012
+ return job_item;
1013
}
1014
1015
int dyn_conf_init(void)
1021
}
1022
}
1023
889
- plugins_dict = dictionary_create(DICT_OPTION_VALUE_LINK_DONT_CLONE);
890
- dictionary_register_delete_callback(plugins_dict, plugin_del_cb, NULL);
891
-
1024
return 0;
1025
}
1026
1048
1049
while (!netdata_exit) {
1050
struct deferred_cfg_send *dcs = deferred_config_pop(ptr);
1051
+ DICTIONARY *plugins_dict = dcs->plugins_dict;
1052
+#ifdef NETDATA_INTERNAL_CHECKS
1053
+ if (plugins_dict == NULL) {
1054
+ fatal("DYNCFG, plugins_dict is NULL");
1055
+ deferred_config_free(dcs);
1056
+ continue;
1057
+ }
1058
+#endif
1059
+
1060
const DICTIONARY_ITEM *plugin_item = dictionary_get_and_acquire_item(plugins_dict, dcs->plugin_name);
1061
if (plugin_item == NULL) {
1062
error_report("DYNCFG, plugin %s not found", dcs->plugin_name);
1067
if (dcs->module_name == NULL) {
1068
dyncfg_config_t cfg = load_config(dcs->plugin_name, NULL, NULL);
1069
if (cfg.data != NULL) {
929
- plugin->set_config_cb(plugin->cb_usr_ctx, &cfg);
1070
+ plugin->set_config_cb(plugin->cb_usr_ctx, plugin->name, &cfg);
1071
freez(cfg.data);
1072
}
1073
} else if (dcs->job_name == NULL) {
1074
dyncfg_config_t cfg = load_config(dcs->plugin_name, dcs->module_name, NULL);
1075
if (cfg.data != NULL) {
1076
struct module *mod = get_module_by_name(plugin, dcs->module_name);
936
- mod->set_config_cb(mod->config_cb_usr_ctx, mod->name, &cfg);
1077
+ mod->set_config_cb(mod->config_cb_usr_ctx, plugin->name, mod->name, &cfg);
1078
freez(cfg.data);
1079
}
1080
} else {
1081
dyncfg_config_t cfg = load_config(dcs->plugin_name, dcs->module_name, dcs->job_name);
1082
if (cfg.data != NULL) {
1083
struct module *mod = get_module_by_name(plugin, dcs->module_name);
943
- mod->set_job_config_cb(mod->job_config_cb_usr_ctx, mod->name, dcs->job_name, &cfg);
1084
+ mod->set_job_config_cb(mod->job_config_cb_usr_ctx, plugin->name, mod->name, dcs->job_name, &cfg);
1085
freez(cfg.data);
1086
}
1087
}
1092
netdata_thread_cleanup_pop(1);
1093
return NULL;
1094
}
1095
+
1096
+bool is_dyncfg_function(const char *function_name, uint8_t type) {
1097
+ // TODO add hash to speed things up
1098
+ if (type & (DYNCFG_FUNCTION_TYPE_GET | DYNCFG_FUNCTION_TYPE_REGULAR)) {
1099
+ if (strncmp(function_name, FUNCTION_NAME_GET_PLUGIN_CONFIG, strlen(FUNCTION_NAME_GET_PLUGIN_CONFIG)) == 0)
1100
+ return true;
1101
+ if (strncmp(function_name, FUNCTION_NAME_GET_PLUGIN_CONFIG_SCHEMA, strlen(FUNCTION_NAME_GET_PLUGIN_CONFIG_SCHEMA)) == 0)
1102
+ return true;
1103
+ if (strncmp(function_name, FUNCTION_NAME_GET_MODULE_CONFIG, strlen(FUNCTION_NAME_GET_MODULE_CONFIG)) == 0)
1104
+ return true;
1105
+ if (strncmp(function_name, FUNCTION_NAME_GET_MODULE_CONFIG_SCHEMA, strlen(FUNCTION_NAME_GET_MODULE_CONFIG_SCHEMA)) == 0)
1106
+ return true;
1107
+ if (strncmp(function_name, FUNCTION_NAME_GET_JOB_CONFIG, strlen(FUNCTION_NAME_GET_JOB_CONFIG)) == 0)
1108
+ return true;
1109
+ if (strncmp(function_name, FUNCTION_NAME_GET_JOB_CONFIG_SCHEMA, strlen(FUNCTION_NAME_GET_JOB_CONFIG_SCHEMA)) == 0)
1110
+ return true;
1111
+ }
1112
+
1113
+ if (type & (DYNCFG_FUNCTION_TYPE_SET | DYNCFG_FUNCTION_TYPE_PAYLOAD)) {
1114
+ if (strncmp(function_name, FUNCTION_NAME_SET_PLUGIN_CONFIG, strlen(FUNCTION_NAME_SET_PLUGIN_CONFIG)) == 0)
1115
+ return true;
1116
+ if (strncmp(function_name, FUNCTION_NAME_SET_MODULE_CONFIG, strlen(FUNCTION_NAME_SET_MODULE_CONFIG)) == 0)
1117
+ return true;
1118
+ if (strncmp(function_name, FUNCTION_NAME_SET_JOB_CONFIG, strlen(FUNCTION_NAME_SET_JOB_CONFIG)) == 0)
1119
+ return true;
1120
+ }
1121
+
1122
+ if (type & (DYNCFG_FUNCTION_TYPE_DELETE | DYNCFG_FUNCTION_TYPE_REGULAR)) {
1123
+ if (strncmp(function_name, FUNCTION_NAME_DELETE_JOB, strlen(FUNCTION_NAME_DELETE_JOB)) == 0)
1124
+ return true;
1125
+ }
1126
+
1127
+ return false;
1128
+}