summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/config/appconfig_migrate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnetdata/config/appconfig_migrate.c')
-rw-r--r--src/libnetdata/config/appconfig_migrate.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/libnetdata/config/appconfig_migrate.c b/src/libnetdata/config/appconfig_migrate.c
new file mode 100644
index 00000000..0c21ec06
--- /dev/null
+++ b/src/libnetdata/config/appconfig_migrate.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "appconfig_internals.h"
+
+int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new) {
+ struct config_option *opt_old, *opt_new;
+ int ret = -1;
+
+ netdata_log_debug(D_CONFIG, "request to rename config in section '%s', old name '%s', to section '%s', new name '%s'", section_old, name_old, section_new, name_new);
+
+ struct config_section *sect_old = appconfig_section_find(root, section_old);
+ if(!sect_old) return ret;
+
+ struct config_section *sect_new = appconfig_section_find(root, section_new);
+ if(!sect_new) sect_new = appconfig_section_create(root, section_new);
+
+ SECTION_LOCK(sect_old);
+ if(sect_old != sect_new)
+ SECTION_LOCK(sect_new);
+
+ opt_old = appconfig_option_find(sect_old, name_old);
+ if(!opt_old) goto cleanup;
+
+ opt_new = appconfig_option_find(sect_new, name_new);
+ if(opt_new) goto cleanup;
+
+ if(unlikely(appconfig_option_del(sect_old, opt_old) != opt_old))
+ netdata_log_error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted the wrong config entry.",
+ string2str(opt_old->name), string2str(sect_old->name));
+
+ // remember the old position of the item
+ struct config_option *opt_old_next = (sect_old == sect_new) ? opt_old->next : NULL;
+
+ DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(sect_old->values, opt_old, prev, next);
+
+ nd_log(NDLS_DAEMON, NDLP_WARNING,
+ "CONFIG: option '[%s].%s' has been migrated to '[%s].%s'.",
+ section_old, name_old,
+ section_new, name_new);
+
+ if(!opt_old->migrated.name) {
+ string_freez(opt_old->migrated.section);
+ opt_old->migrated.section = string_dup(sect_old->name);
+ opt_old->migrated.name = opt_old->name;
+ }
+ else
+ string_freez(opt_old->name);
+
+ opt_old->name = string_strdupz(name_new);
+ opt_old->flags |= CONFIG_VALUE_MIGRATED;
+
+ opt_new = opt_old;
+
+ // put in the list, but try to keep the order
+ if(opt_old_next && sect_old == sect_new)
+ DOUBLE_LINKED_LIST_INSERT_ITEM_BEFORE_UNSAFE(sect_new->values, opt_old_next, opt_new, prev, next);
+ else {
+ // we don't have the old next item (probably a different section?)
+ // find the last MIGRATED one
+ struct config_option *t = sect_new->values ? sect_new->values->prev : NULL;
+ for (; t && t != sect_new->values ; t = t->prev) {
+ if (t->flags & CONFIG_VALUE_MIGRATED)
+ break;
+ }
+ if (t == sect_new->values)
+ DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(sect_new->values, opt_new, prev, next);
+ else
+ DOUBLE_LINKED_LIST_INSERT_ITEM_AFTER_UNSAFE(sect_new->values, t, opt_new, prev, next);
+ }
+
+ if(unlikely(appconfig_option_add(sect_new, opt_old) != opt_old))
+ netdata_log_error("INTERNAL ERROR: re-indexing of config '%s' in section '%s', already exists.",
+ string2str(opt_old->name), string2str(sect_new->name));
+
+ ret = 0;
+
+cleanup:
+ if(sect_old != sect_new)
+ SECTION_UNLOCK(sect_new);
+ SECTION_UNLOCK(sect_old);
+ return ret;
+}
+
+int appconfig_move_everywhere(struct config *root, const char *name_old, const char *name_new) {
+ int ret = -1;
+ APPCONFIG_LOCK(root);
+ struct config_section *sect;
+ for(sect = root->sections; sect; sect = sect->next) {
+ if(appconfig_move(root, string2str(sect->name), name_old, string2str(sect->name), name_new) == 0)
+ ret = 0;
+ }
+ APPCONFIG_UNLOCK(root);
+ return ret;
+}
+