summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStelios Fragkakis <52996999+stelfrag@users.noreply.github.com>2023-11-29 15:57:35 +0200
committerGitHub <noreply@github.com>2023-11-29 15:57:35 +0200
commitb1465aa5895326c4100e3b535364ca78f91b6f71 (patch)
treeaca7bf7de036671e8392916c56c8b099e8a79b59
parent4f6fe91a6d3265fecae01c9d3ee136d2d48208db (diff)
When unregistering an ephemeral host, delete its chart labels (#16486)
* When unregistering an ephemeral host, delete its chart labels * Fix memory leak in case of query preparation or bind failure * Add check to handle CID 410125 Dereference null return value
-rw-r--r--collectors/plugins.d/pluginsd_parser.c3
-rw-r--r--database/sqlite/sqlite_aclk.c27
-rw-r--r--database/sqlite/sqlite_metadata.c87
-rw-r--r--database/sqlite/sqlite_metadata.h1
4 files changed, 106 insertions, 12 deletions
diff --git a/collectors/plugins.d/pluginsd_parser.c b/collectors/plugins.d/pluginsd_parser.c
index f26c5fb08c..246043a375 100644
--- a/collectors/plugins.d/pluginsd_parser.c
+++ b/collectors/plugins.d/pluginsd_parser.c
@@ -1422,7 +1422,8 @@ static inline PARSER_RC pluginsd_label(char **words, size_t num_words, PARSER *p
int is_ephemeral = appconfig_test_boolean_value((char *) value);
if (is_ephemeral) {
RRDHOST *host = pluginsd_require_scope_host(parser, PLUGINSD_KEYWORD_LABEL);
- rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST);
+ if (likely(host))
+ rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST);
}
}
diff --git a/database/sqlite/sqlite_aclk.c b/database/sqlite/sqlite_aclk.c
index 83203b22e3..480148137d 100644
--- a/database/sqlite/sqlite_aclk.c
+++ b/database/sqlite/sqlite_aclk.c
@@ -257,30 +257,38 @@ static void sql_unregister_node(char *machine_guid)
return;
rc = uuid_parse(machine_guid, host_uuid);
- freez(machine_guid);
- if (rc)
+ if (rc) {
+ freez(machine_guid);
return;
+ }
sqlite3_stmt *res = NULL;
rc = sqlite3_prepare_v2(db_meta, "UPDATE node_instance SET node_id = NULL WHERE host_id = @host_id", -1, &res, 0);
if (unlikely(rc != SQLITE_OK)) {
- error_report("Failed to prepare statement remote node id for a host");
+ error_report("Failed to prepare statement to remove the host node id");
+ freez(machine_guid);
return;
}
rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC);
if (unlikely(rc != SQLITE_OK)) {
- error_report("Failed to bind host_id parameter to remove node id");
- goto failed;
+ error_report("Failed to bind host_id parameter to remove host node id");
+ goto skip;
}
rc = sqlite3_step_monitored(res);
- if (unlikely(rc != SQLITE_DONE))
- error_report("Failed to execute command to remove node id");
+ if (unlikely(rc != SQLITE_DONE)) {
+ error_report("Failed to execute command to remove host node id");
+ } else {
+ // node: machine guid will be freed after processing
+ metadata_delete_host_chart_labels(machine_guid);
+ machine_guid = NULL;
+ }
-failed:
+skip:
if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
- error_report("Failed to finalize statement to remove node id");
+ error_report("Failed to finalize statement to remove host node id");
+ freez(machine_guid);
}
@@ -448,6 +456,7 @@ static void aclk_synchronization(void *arg __maybe_unused)
break;
case ACLK_DATABASE_NODE_UNREGISTER:
sql_unregister_node(cmd.param[0]);
+
break;
// ALERTS
case ACLK_DATABASE_PUSH_ALERT_CONFIG:
diff --git a/database/sqlite/sqlite_metadata.c b/database/sqlite/sqlite_metadata.c
index 70af4809c8..f2ce7ea913 100644
--- a/database/sqlite/sqlite_metadata.c
+++ b/database/sqlite/sqlite_metadata.c
@@ -80,6 +80,7 @@ enum metadata_opcode {
METADATA_ADD_HOST_INFO,
METADATA_SCAN_HOSTS,
METADATA_LOAD_HOST_CONTEXT,
+ METADATA_DELETE_HOST_CHART_LABELS,
METADATA_MAINTENANCE,
METADATA_SYNC_SHUTDOWN,
METADATA_UNITTEST,
@@ -119,6 +120,8 @@ struct metadata_wc {
#define metadata_flag_set(target_flags, flag) __atomic_or_fetch(&((target_flags)->flags), (flag), __ATOMIC_SEQ_CST)
#define metadata_flag_clear(target_flags, flag) __atomic_and_fetch(&((target_flags)->flags), ~(flag), __ATOMIC_SEQ_CST)
+struct metadata_wc metasync_worker = {.loop = NULL};
+
//
// For unittest
//
@@ -138,6 +141,33 @@ struct query_build {
char uuid_str[UUID_STR_LEN];
};
+#define SQL_DELETE_CHART_LABELS_BY_HOST \
+ "DELETE FROM chart_label WHERE chart_id in (SELECT chart_id FROM chart WHERE host_id = @host_id)"
+
+static void delete_host_chart_labels(uuid_t *host_uuid)
+{
+ sqlite3_stmt *res = NULL;
+
+ int rc = sqlite3_prepare_v2(db_meta, SQL_DELETE_CHART_LABELS_BY_HOST, -1, &res, 0);
+ if (unlikely(rc != SQLITE_OK)) {
+ error_report("Failed to prepare statement to delete chart labels by host");
+ return;
+ }
+
+ rc = sqlite3_bind_blob(res, 1, host_uuid, sizeof(*host_uuid), SQLITE_STATIC);
+ if (unlikely(rc != SQLITE_OK)) {
+ error_report("Failed to bind host_id parameter to host chart labels");
+ goto failed;
+ }
+ rc = sqlite3_step_monitored(res);
+ if (unlikely(rc != SQLITE_DONE))
+ error_report("Failed to execute command to remove host chart labels");
+
+failed:
+ if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
+ error_report("Failed to finalize statement to remove host chart labels");
+}
+
static int host_label_store_to_sql_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
struct query_build *lb = data;
if (unlikely(!lb->count))
@@ -1173,6 +1203,7 @@ void run_metadata_cleanup(struct metadata_wc *wc)
struct scan_metadata_payload {
uv_work_t request;
struct metadata_wc *wc;
+ void *data;
BUFFER *work_buffer;
uint32_t max_count;
};
@@ -1411,6 +1442,11 @@ static void store_host_and_system_info(RRDHOST *host, size_t *query_counter)
}
}
+struct host_chart_label_cleanup {
+ Pvoid_t JudyL;
+ Word_t count;
+};
+
// Worker thread to scan hosts for pending metadata to store
static void start_metadata_hosts(uv_work_t *req __maybe_unused)
{
@@ -1427,6 +1463,29 @@ static void start_metadata_hosts(uv_work_t *req __maybe_unused)
internal_error(true, "METADATA: checking all hosts...");
usec_t started_ut = now_monotonic_usec(); (void)started_ut;
+ struct host_chart_label_cleanup *cl_cleanup_data = data->data;
+
+ if (cl_cleanup_data) {
+ Word_t Index = 0;
+ bool first = true;
+ Pvoid_t *PValue;
+ while ((PValue = JudyLFirstThenNext(cl_cleanup_data->JudyL, &Index, &first))) {
+ char *machine_guid = *PValue;
+
+ host = rrdhost_find_by_guid(machine_guid);
+ if (unlikely(host))
+ continue;
+
+ uuid_t host_uuid;
+ uuid_parse(machine_guid, host_uuid);
+ delete_host_chart_labels(&host_uuid);
+
+ freez(machine_guid);
+ }
+ JudyLFreeArray(&cl_cleanup_data->JudyL, PJE0);
+ freez(cl_cleanup_data);
+ }
+
bool run_again = false;
worker_is_busy(UV_EVENT_METADATA_STORE);
@@ -1568,6 +1627,7 @@ static void metadata_event_loop(void *arg)
completion_mark_complete(&wc->start_stop_complete);
BUFFER *work_buffer = buffer_create(1024, &netdata_buffers_statistics.buffers_sqlite);
struct scan_metadata_payload *data;
+ struct host_chart_label_cleanup *cl_cleanup_data = NULL;
while (shutdown == 0 || (wc->flags & METADATA_FLAG_PROCESSING)) {
uuid_t *uuid;
@@ -1624,7 +1684,9 @@ static void metadata_event_loop(void *arg)
data = mallocz(sizeof(*data));
data->request.data = data;
data->wc = wc;
+ data->data = cl_cleanup_data;
data->work_buffer = work_buffer;
+ cl_cleanup_data = NULL;
if (unlikely(cmd.completion)) {
data->max_count = 0; // 0 will process all pending updates
@@ -1640,6 +1702,7 @@ static void metadata_event_loop(void *arg)
after_metadata_hosts))) {
// Failed to launch worker -- let the event loop handle completion
cmd.completion = wc->scan_complete;
+ cl_cleanup_data = data->data;
freez(data);
metadata_flag_clear(wc, METADATA_FLAG_PROCESSING);
}
@@ -1657,6 +1720,15 @@ static void metadata_event_loop(void *arg)
freez(data);
}
break;
+ case METADATA_DELETE_HOST_CHART_LABELS:;
+ if (!cl_cleanup_data)
+ cl_cleanup_data = callocz(1,sizeof(*cl_cleanup_data));
+
+ Pvoid_t *PValue = JudyLIns(&cl_cleanup_data->JudyL, (Word_t) ++cl_cleanup_data->count, PJE0);
+ if (PValue)
+ *PValue = (void *) cmd.param[0];
+
+ break;
case METADATA_UNITTEST:;
struct thread_unittest *tu = (struct thread_unittest *) cmd.param[0];
sleep_usec(1000); // processing takes 1ms
@@ -1702,8 +1774,6 @@ error_after_loop_init:
worker_unregister();
}
-struct metadata_wc metasync_worker = {.loop = NULL};
-
void metadata_sync_shutdown(void)
{
completion_init(&metasync_worker.start_stop_complete);
@@ -1828,6 +1898,19 @@ void metadata_queue_load_host_context(RRDHOST *host)
nd_log(NDLS_DAEMON, NDLP_DEBUG, "Queued command to load host contexts");
}
+void metadata_delete_host_chart_labels(char *machine_guid)
+{
+ if (unlikely(!metasync_worker.loop)) {
+ freez(machine_guid);
+ return;
+ }
+
+ // Node machine guid is already strdup-ed
+ queue_metadata_cmd(METADATA_DELETE_HOST_CHART_LABELS, machine_guid, NULL);
+ nd_log(NDLS_DAEMON, NDLP_DEBUG, "Queued command delete chart labels for host %s", machine_guid);
+}
+
+
//
// unitests
//
diff --git a/database/sqlite/sqlite_metadata.h b/database/sqlite/sqlite_metadata.h
index f75a9ab00f..6860cfedf8 100644
--- a/database/sqlite/sqlite_metadata.h
+++ b/database/sqlite/sqlite_metadata.h
@@ -17,6 +17,7 @@ void metaqueue_host_update_info(RRDHOST *host);
void metaqueue_ml_load_models(RRDDIM *rd);
void migrate_localhost(uuid_t *host_uuid);
void metadata_queue_load_host_context(RRDHOST *host);
+void metadata_delete_host_chart_labels(char *machine_guid);
void vacuum_database(sqlite3 *database, const char *db_alias, int threshold, int vacuum_pc);
// UNIT TEST