Handle ephemeral hosts (#16381)
* Handle ephemeral hosts * Node empheral removal timeout 86400 seconds (1 day) * Move config from health to global section * Set a node to queryable false when it is ephemeral and is removed * Log queryable. Send queryable=0 only when forcing host deletion (the node is ephemeral) * Switch to "is ephemeral node" Document stream.conf * Unregister node id
Stelios Fragkakis committed
Nov 23, 2023 at 23:56 UTC
85f359fc2677752ef7501fbee92d9caecc924538
15 files changed
+305
-162
aclk/aclk.c
+5
-6
@@ -917,7 +917,7 @@ exit:
917
return NULL;
918
}
919
920
-void aclk_host_state_update(RRDHOST *host, int cmd)
920
+void aclk_host_state_update(RRDHOST *host, int cmd, int queryable)
921
{
922
uuid_t node_id;
923
int ret = 0;
@@ -962,7 +962,7 @@ void aclk_host_state_update(RRDHOST *host, int cmd)
962
node_instance_connection_t node_state_update = {
963
.hops = host->system_info->hops,
964
.live = cmd,
965
- .queryable = 1,
965
+ .queryable = queryable,
966
.session_id = aclk_session_newarch
967
};
968
node_state_update.node_id = mallocz(UUID_STR_LEN);
@@ -976,9 +976,8 @@ void aclk_host_state_update(RRDHOST *host, int cmd)
976
rrdhost_aclk_state_unlock(localhost);
977
978
nd_log(NDLS_DAEMON, NDLP_DEBUG,
979
- "Queuing status update for node=%s, live=%d, hops=%u",
980
- (char*)node_state_update.node_id, cmd, host->system_info->hops);
981
-
979
+ "Queuing status update for node=%s, live=%d, hops=%u, queryable=%d",
980
+ (char*)node_state_update.node_id, cmd, host->system_info->hops, queryable);
981
freez((void*)node_state_update.node_id);
982
query->data.bin_payload.msg_name = "UpdateNodeInstanceConnection";
983
query->data.bin_payload.topic = ACLK_TOPICID_NODE_CONN;
@@ -1022,7 +1021,7 @@ void aclk_send_node_instances()
1021
rrdhost_aclk_state_unlock(localhost);
1022
1023
nd_log(NDLS_DAEMON, NDLP_DEBUG,
1025
- "Queuing status update for node=%s, live=%d, hops=%d",
1024
+ "Queuing status update for node=%s, live=%d, hops=%d, queryable=1",
1025
(char*)node_state_update.node_id, list->live, list->hops);
1026
1027
freez((void*)node_state_update.capabilities);
aclk/aclk.h
+1
-1
@@ -75,7 +75,7 @@ extern struct aclk_shared_state {
75
int mqtt_shutdown_msg_rcvd;
76
} aclk_shared_state;
77
78
-void aclk_host_state_update(RRDHOST *host, int cmd);
78
+void aclk_host_state_update(RRDHOST *host, int cmd, int queryable);
79
void aclk_send_node_instances(void);
80
81
void aclk_send_bin_msg(char *msg, size_t msg_len, enum aclk_topics subtopic, const char *msgname);
collectors/plugins.d/pluginsd_parser.c
+33
-24
@@ -566,30 +566,29 @@ static inline PARSER_RC pluginsd_host_define_end(char **words __maybe_unused, si
566
return PLUGINSD_DISABLE_PLUGIN(parser, PLUGINSD_KEYWORD_HOST_DEFINE_END, "missing initialization, send " PLUGINSD_KEYWORD_HOST_DEFINE " before this");
567
568
RRDHOST *host = rrdhost_find_or_create(
569
- string2str(parser->user.host_define.hostname),
570
- string2str(parser->user.host_define.hostname),
571
- parser->user.host_define.machine_guid_str,
572
- "Netdata Virtual Host 1.0",
573
- netdata_configured_timezone,
574
- netdata_configured_abbrev_timezone,
575
- netdata_configured_utc_offset,
576
- NULL,
577
- program_name,
578
- program_version,
579
- default_rrd_update_every,
580
- default_rrd_history_entries,
581
- default_rrd_memory_mode,
582
- default_health_enabled,
583
- default_rrdpush_enabled,
584
- default_rrdpush_destination,
585
- default_rrdpush_api_key,
586
- default_rrdpush_send_charts_matching,
587
- default_rrdpush_enable_replication,
588
- default_rrdpush_seconds_to_replicate,
589
- default_rrdpush_replication_step,
590
- rrdhost_labels_to_system_info(parser->user.host_define.rrdlabels),
591
- false
592
- );
569
+ string2str(parser->user.host_define.hostname),
570
+ string2str(parser->user.host_define.hostname),
571
+ parser->user.host_define.machine_guid_str,
572
+ "Netdata Virtual Host 1.0",
573
+ netdata_configured_timezone,
574
+ netdata_configured_abbrev_timezone,
575
+ netdata_configured_utc_offset,
576
+ NULL,
577
+ program_name,
578
+ program_version,
579
+ default_rrd_update_every,
580
+ default_rrd_history_entries,
581
+ default_rrd_memory_mode,
582
+ default_health_enabled,
583
+ default_rrdpush_enabled,
584
+ default_rrdpush_destination,
585
+ default_rrdpush_api_key,
586
+ default_rrdpush_send_charts_matching,
587
+ default_rrdpush_enable_replication,
588
+ default_rrdpush_seconds_to_replicate,
589
+ default_rrdpush_replication_step,
590
+ rrdhost_labels_to_system_info(parser->user.host_define.rrdlabels),
591
+ false);
592
593
rrdhost_option_set(host, RRDHOST_OPTION_VIRTUAL_HOST);
594
@@ -1412,6 +1411,14 @@ static inline PARSER_RC pluginsd_label(char **words, size_t num_words, PARSER *p
1411
if(unlikely(!(parser->user.new_host_labels)))
1412
parser->user.new_host_labels = rrdlabels_create();
1413
1414
+ if (strcmp(name,HOST_LABEL_IS_EPHEMERAL) == 0) {
1415
+ int is_ephemeral = appconfig_test_boolean_value((char *) value);
1416
+ if (is_ephemeral) {
1417
+ RRDHOST *host = pluginsd_require_scope_host(parser, PLUGINSD_KEYWORD_LABEL);
1418
+ rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST);
1419
+ }
1420
+ }
1421
+
1422
rrdlabels_add(parser->user.new_host_labels, name, store, str2l(label_source));
1423
1424
if (allocated_store)
@@ -1430,6 +1437,8 @@ static inline PARSER_RC pluginsd_overwrite(char **words __maybe_unused, size_t n
1437
host->rrdlabels = rrdlabels_create();
1438
1439
rrdlabels_migrate_to_these(host->rrdlabels, parser->user.new_host_labels);
1440
+ if (rrdhost_option_check(host, RRDHOST_OPTION_EPHEMERAL_HOST))
1441
+ rrdlabels_add(host->rrdlabels, HOST_LABEL_IS_EPHEMERAL, "true", RRDLABEL_SRC_CONFIG);
1442
rrdhost_flag_set(host, RRDHOST_FLAG_METADATA_LABELS | RRDHOST_FLAG_METADATA_UPDATE);
1443
1444
rrdlabels_destroy(parser->user.new_host_labels);
collectors/plugins.d/pluginsd_parser.h
+1
@@ -15,6 +15,7 @@
15
16
#define PLUGINSD_MIN_RRDSET_POINTERS_CACHE 1024
17
18
+#define HOST_LABEL_IS_EPHEMERAL "_is_ephemeral"
19
// PARSER return codes
20
typedef enum __attribute__ ((__packed__)) parser_rc {
21
PARSER_RC_OK, // Callback was successful, go on
daemon/main.c
+6
@@ -1077,6 +1077,11 @@ static void backwards_compatible_config() {
1077
1078
config_move(CONFIG_SECTION_LOGS, "errors flood protection period",
1079
CONFIG_SECTION_LOGS, "logs flood protection period");
1080
+ config_move(CONFIG_SECTION_HEALTH, "is ephemeral",
1081
+ CONFIG_SECTION_GLOBAL, "is ephemeral node");
1082
+
1083
+ config_move(CONFIG_SECTION_HEALTH, "has unstable connection",
1084
+ CONFIG_SECTION_GLOBAL, "has unstable connection");
1085
}
1086
1087
static int get_hostname(char *buf, size_t buf_size) {
@@ -1223,6 +1228,7 @@ static void get_netdata_configured_variables() {
1228
// --------------------------------------------------------------------
1229
1230
rrdset_free_obsolete_time_s = config_get_number(CONFIG_SECTION_DB, "cleanup obsolete charts after secs", rrdset_free_obsolete_time_s);
1231
+ rrdhost_free_ephemeral_time_s = config_get_number(CONFIG_SECTION_DB, "cleanup ephemeral hosts after secs", rrdhost_free_ephemeral_time_s);
1232
// Current chart locking and invalidation scheme doesn't prevent Netdata from segmentation faults if a short
1233
// cleanup delay is set. Extensive stress tests showed that 10 seconds is quite a safe delay. Look at
1234
// https://github.com/netdata/netdata/pull/11222#issuecomment-868367920 for more information.
daemon/service.c
+35
-12
@@ -272,22 +272,45 @@ restart_after_removal:
272
if(!rrdhost_should_be_removed(host, protected_host, now))
273
continue;
274
275
- netdata_log_info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", rrdhost_hostname(host), host->machine_guid);
276
-
277
- if (rrdhost_option_check(host, RRDHOST_OPTION_DELETE_ORPHAN_HOST)
278
- /* don't delete multi-host DB host files */
279
- && !(host->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE && is_storage_engine_shared(host->db[0].instance))
280
- ) {
281
- worker_is_busy(WORKER_JOB_DELETE_HOST_CHARTS);
282
- rrdhost_delete_charts(host);
275
+ bool is_archived = rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED);
276
+ if (!is_archived) {
277
+ netdata_log_info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", rrdhost_hostname(host), host->machine_guid);
278
+
279
+ if (rrdhost_option_check(host, RRDHOST_OPTION_DELETE_ORPHAN_HOST)
280
+ /* don't delete multi-host DB host files */
281
+ && !(host->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE && is_storage_engine_shared(host->db[0].instance))
282
+ ) {
283
+ worker_is_busy(WORKER_JOB_DELETE_HOST_CHARTS);
284
+ rrdhost_delete_charts(host);
285
+ }
286
+ else {
287
+ worker_is_busy(WORKER_JOB_SAVE_HOST_CHARTS);
288
+ rrdhost_save_charts(host);
289
+ }
290
}
284
- else {
285
- worker_is_busy(WORKER_JOB_SAVE_HOST_CHARTS);
286
- rrdhost_save_charts(host);
291
+
292
+ bool force = false;
293
+
294
+ if (rrdhost_option_check(host, RRDHOST_OPTION_EPHEMERAL_HOST) && now - host->last_connected > rrdhost_free_ephemeral_time_s)
295
+ force = true;
296
+
297
+ if (!force && is_archived)
298
+ continue;
299
+
300
+ if (force) {
301
+ netdata_log_info("Host '%s' with machine guid '%s' is archived, ephemeral clean up.", rrdhost_hostname(host), host->machine_guid);
302
}
303
304
worker_is_busy(WORKER_JOB_FREE_HOST);
290
- rrdhost_free___while_having_rrd_wrlock(host, false);
305
+#ifdef ENABLE_ACLK
306
+ // in case we have cloud connection we inform cloud
307
+ // a child disconnected
308
+ if (netdata_cloud_enabled && force) {
309
+ aclk_host_state_update(host, 0, 0);
310
+ unregister_node(host->machine_guid);
311
+ }
312
+#endif
313
+ rrdhost_free___while_having_rrd_wrlock(host, force);
314
goto restart_after_removal;
315
}
316
daemon/unit_test.c
+23
-24
@@ -1824,30 +1824,29 @@ static RRDHOST *dbengine_rrdhost_find_or_create(char *name)
1824
/* We don't want to drop metrics when generating load, we prefer to block data generation itself */
1825
1826
return rrdhost_find_or_create(
1827
- name
1828
- , name
1829
- , name
1830
- , os_type
1831
- , netdata_configured_timezone
1832
- , netdata_configured_abbrev_timezone
1833
- , netdata_configured_utc_offset
1834
- , ""
1835
- , program_name
1836
- , program_version
1837
- , default_rrd_update_every
1838
- , default_rrd_history_entries
1839
- , RRD_MEMORY_MODE_DBENGINE
1840
- , default_health_enabled
1841
- , default_rrdpush_enabled
1842
- , default_rrdpush_destination
1843
- , default_rrdpush_api_key
1844
- , default_rrdpush_send_charts_matching
1845
- , default_rrdpush_enable_replication
1846
- , default_rrdpush_seconds_to_replicate
1847
- , default_rrdpush_replication_step
1848
- , NULL
1849
- , 0
1850
- );
1827
+ name,
1828
+ name,
1829
+ name,
1830
+ os_type,
1831
+ netdata_configured_timezone,
1832
+ netdata_configured_abbrev_timezone,
1833
+ netdata_configured_utc_offset,
1834
+ "",
1835
+ program_name,
1836
+ program_version,
1837
+ default_rrd_update_every,
1838
+ default_rrd_history_entries,
1839
+ RRD_MEMORY_MODE_DBENGINE,
1840
+ default_health_enabled,
1841
+ default_rrdpush_enabled,
1842
+ default_rrdpush_destination,
1843
+ default_rrdpush_api_key,
1844
+ default_rrdpush_send_charts_matching,
1845
+ default_rrdpush_enable_replication,
1846
+ default_rrdpush_seconds_to_replicate,
1847
+ default_rrdpush_replication_step,
1848
+ NULL,
1849
+ 0);
1850
}
1851
1852
// constants for test_dbengine
database/rrd.h
+25
-24
@@ -1043,6 +1043,7 @@ typedef enum __attribute__ ((__packed__)) {
1043
RRDHOST_OPTION_REPLICATION = (1 << 5), // when set, we support replication for this host
1044
1045
RRDHOST_OPTION_VIRTUAL_HOST = (1 << 6), // when set, this host is a virtual one
1046
+ RRDHOST_OPTION_EPHEMERAL_HOST = (1 << 7), // when set, this host is an ephemeral one
1047
} RRDHOST_OPTIONS;
1048
1049
#define rrdhost_option_check(host, flag) ((host)->options & (flag))
@@ -1426,6 +1427,7 @@ void rrddim_index_destroy(RRDSET *st);
1427
// ----------------------------------------------------------------------------
1428
1429
extern time_t rrdhost_free_orphan_time_s;
1430
+extern time_t rrdhost_free_ephemeral_time_s;
1431
1432
int rrd_init(char *hostname, struct rrdhost_system_info *system_info, bool unittest);
1433
@@ -1434,30 +1436,29 @@ RRDHOST *rrdhost_find_by_guid(const char *guid);
1436
RRDHOST *find_host_by_node_id(char *node_id);
1437
1438
RRDHOST *rrdhost_find_or_create(
1437
- const char *hostname
1438
- , const char *registry_hostname
1439
- , const char *guid
1440
- , const char *os
1441
- , const char *timezone
1442
- , const char *abbrev_timezone
1443
- , int32_t utc_offset
1444
- , const char *tags
1445
- , const char *program_name
1446
- , const char *program_version
1447
- , int update_every
1448
- , long history
1449
- , RRD_MEMORY_MODE mode
1450
- , unsigned int health_enabled
1451
- , unsigned int rrdpush_enabled
1452
- , char *rrdpush_destination
1453
- , char *rrdpush_api_key
1454
- , char *rrdpush_send_charts_matching
1455
- , bool rrdpush_enable_replication
1456
- , time_t rrdpush_seconds_to_replicate
1457
- , time_t rrdpush_replication_step
1458
- , struct rrdhost_system_info *system_info
1459
- , bool is_archived
1460
-);
1439
+ const char *hostname,
1440
+ const char *registry_hostname,
1441
+ const char *guid,
1442
+ const char *os,
1443
+ const char *timezone,
1444
+ const char *abbrev_timezone,
1445
+ int32_t utc_offset,
1446
+ const char *tags,
1447
+ const char *program_name,
1448
+ const char *program_version,
1449
+ int update_every,
1450
+ long history,
1451
+ RRD_MEMORY_MODE mode,
1452
+ unsigned int health_enabled,
1453
+ unsigned int rrdpush_enabled,
1454
+ char *rrdpush_destination,
1455
+ char *rrdpush_api_key,
1456
+ char *rrdpush_send_charts_matching,
1457
+ bool rrdpush_enable_replication,
1458
+ time_t rrdpush_seconds_to_replicate,
1459
+ time_t rrdpush_replication_step,
1460
+ struct rrdhost_system_info *system_info,
1461
+ bool is_archived);
1462
1463
int rrdhost_set_system_info_variable(struct rrdhost_system_info *system_info, char *name, char *value);
1464
database/rrdhost.c
+10
-2
@@ -31,6 +31,7 @@ netdata_rwlock_t rrd_rwlock = NETDATA_RWLOCK_INITIALIZER;
31
32
time_t rrdset_free_obsolete_time_s = 3600;
33
time_t rrdhost_free_orphan_time_s = 3600;
34
+time_t rrdhost_free_ephemeral_time_s = 86400;
35
36
bool is_storage_engine_shared(STORAGE_INSTANCE *engine __maybe_unused) {
37
#ifdef ENABLE_DBENGINE
@@ -838,7 +839,7 @@ inline int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected_host, tim
839
&& rrdhost_receiver_replicating_charts(host) == 0
840
&& rrdhost_sender_replicating_charts(host) == 0
841
&& rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN)
841
- && !rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED)
842
+ && !rrdhost_flag_check(host, RRDHOST_FLAG_PENDING_CONTEXT_LOAD)
843
&& !host->receiver
844
&& host->child_disconnected_time
845
&& host->child_disconnected_time + rrdhost_free_orphan_time_s < now_s)
@@ -1464,7 +1465,14 @@ static void rrdhost_load_auto_labels(void) {
1465
1466
add_aclk_host_labels();
1467
1467
- health_add_host_labels();
1468
+ // The source should be CONF, but when it is set, these labels are exported by default ('send configured labels' in exporting.conf).
1469
+ // Their export seems to break exporting to Graphite, see https://github.com/netdata/netdata/issues/14084.
1470
+
1471
+ int is_ephemeral = appconfig_get_boolean(&netdata_config, CONFIG_SECTION_GLOBAL, "is ephemeral node", CONFIG_BOOLEAN_NO);
1472
+ rrdlabels_add(labels, "_is_ephemeral", is_ephemeral ? "true" : "false", RRDLABEL_SRC_AUTO);
1473
+
1474
+ int has_unstable_connection = appconfig_get_boolean(&netdata_config, CONFIG_SECTION_GLOBAL, "has unstable connection", CONFIG_BOOLEAN_NO);
1475
+ rrdlabels_add(labels, "_has_unstable_connection", has_unstable_connection ? "true" : "false", RRDLABEL_SRC_AUTO);
1476
1477
rrdlabels_add(labels, "_is_parent", (localhost->connected_children_count > 0) ? "true" : "false", RRDLABEL_SRC_AUTO);
1478
database/sqlite/sqlite_aclk.c
+118
-28
@@ -71,6 +71,7 @@ enum {
71
IDX_ENTRIES,
72
IDX_HEALTH_ENABLED,
73
IDX_LAST_CONNECTED,
74
+ IDX_IS_EPHEMERAL,
75
};
76
77
static int create_host_callback(void *data, int argc, char **argv, char **column)
@@ -79,9 +80,26 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
80
UNUSED(argc);
81
UNUSED(column);
82
83
+ time_t last_connected = (time_t) (argv[IDX_LAST_CONNECTED] ? str2uint64_t(argv[IDX_LAST_CONNECTED], NULL) : 0);
84
+ time_t age = now_realtime_sec() - last_connected;
85
+ int is_ephemeral = 0;
86
+
87
+ if (argv[IDX_IS_EPHEMERAL])
88
+ is_ephemeral = str2i(argv[IDX_IS_EPHEMERAL]);
89
+
90
char guid[UUID_STR_LEN];
91
uuid_unparse_lower(*(uuid_t *)argv[IDX_HOST_ID], guid);
92
93
+ if (is_ephemeral && age > rrdhost_free_ephemeral_time_s) {
94
+ netdata_log_info(
95
+ "Skipping ephemeral hostname \"%s\" with GUID \"%s\", age = %ld seconds (limit %ld seconds)",
96
+ (const char *)argv[IDX_HOSTNAME],
97
+ guid,
98
+ age,
99
+ rrdhost_free_ephemeral_time_s);
100
+ return 0;
101
+ }
102
+
103
struct rrdhost_system_info *system_info = callocz(1, sizeof(struct rrdhost_system_info));
104
__atomic_sub_fetch(&netdata_buffers_statistics.rrdhost_allocations_size, sizeof(struct rrdhost_system_info), __ATOMIC_RELAXED);
105
@@ -90,33 +108,47 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
108
sql_build_host_system_info((uuid_t *)argv[IDX_HOST_ID], system_info);
109
110
RRDHOST *host = rrdhost_find_or_create(
93
- (const char *) argv[IDX_HOSTNAME]
94
- , (const char *) argv[IDX_REGISTRY]
95
- , guid
96
- , (const char *) argv[IDX_OS]
97
- , (const char *) argv[IDX_TIMEZONE]
98
- , (const char *) argv[IDX_ABBREV_TIMEZONE]
99
- , (int32_t) (argv[IDX_UTC_OFFSET] ? str2uint32_t(argv[IDX_UTC_OFFSET], NULL) : 0)
100
- , (const char *) argv[IDX_TAGS]
101
- , (const char *) (argv[IDX_PROGRAM_NAME] ? argv[IDX_PROGRAM_NAME] : "unknown")
102
- , (const char *) (argv[IDX_PROGRAM_VERSION] ? argv[IDX_PROGRAM_VERSION] : "unknown")
103
- , argv[IDX_UPDATE_EVERY] ? str2i(argv[IDX_UPDATE_EVERY]) : 1
104
- , argv[IDX_ENTRIES] ? str2i(argv[IDX_ENTRIES]) : 0
105
- , default_rrd_memory_mode
106
- , 0 // health
107
- , 0 // rrdpush enabled
108
- , NULL //destination
109
- , NULL // api key
110
- , NULL // send charts matching
111
- , false // rrdpush_enable_replication
112
- , 0 // rrdpush_seconds_to_replicate
113
- , 0 // rrdpush_replication_step
114
- , system_info
115
- , 1
116
- );
111
+ (const char *)argv[IDX_HOSTNAME],
112
+ (const char *)argv[IDX_REGISTRY],
113
+ guid,
114
+ (const char *)argv[IDX_OS],
115
+ (const char *)argv[IDX_TIMEZONE],
116
+ (const char *)argv[IDX_ABBREV_TIMEZONE],
117
+ (int32_t)(argv[IDX_UTC_OFFSET] ? str2uint32_t(argv[IDX_UTC_OFFSET], NULL) : 0),
118
+ (const char *)argv[IDX_TAGS],
119
+ (const char *)(argv[IDX_PROGRAM_NAME] ? argv[IDX_PROGRAM_NAME] : "unknown"),
120
+ (const char *)(argv[IDX_PROGRAM_VERSION] ? argv[IDX_PROGRAM_VERSION] : "unknown"),
121
+ argv[IDX_UPDATE_EVERY] ? str2i(argv[IDX_UPDATE_EVERY]) : 1,
122
+ argv[IDX_ENTRIES] ? str2i(argv[IDX_ENTRIES]) : 0,
123
+ default_rrd_memory_mode,
124
+ 0 // health
125
+ ,
126
+ 0 // rrdpush enabled
127
+ ,
128
+ NULL //destination
129
+ ,
130
+ NULL // api key
131
+ ,
132
+ NULL // send charts matching
133
+ ,
134
+ false // rrdpush_enable_replication
135
+ ,
136
+ 0 // rrdpush_seconds_to_replicate
137
+ ,
138
+ 0 // rrdpush_replication_step
139
+ ,
140
+ system_info,
141
+ 1);
142
+
143
if (likely(host)) {
144
+ if (is_ephemeral)
145
+ rrdhost_option_set(host, RRDHOST_OPTION_EPHEMERAL_HOST);
146
+
147
+ if (is_ephemeral)
148
+ host->child_disconnected_time = now_realtime_sec();
149
+
150
host->rrdlabels = sql_load_host_labels((uuid_t *)argv[IDX_HOST_ID]);
119
- host->last_connected = (time_t) (argv[IDX_LAST_CONNECTED] ? str2uint64_t(argv[IDX_LAST_CONNECTED], NULL) : 0);
151
+ host->last_connected = last_connected;
152
}
153
154
(*number_of_chidren)++;
@@ -125,7 +157,7 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
157
char node_str[UUID_STR_LEN] = "<none>";
158
if (likely(host->node_id))
159
uuid_unparse_lower(*host->node_id, node_str);
128
- internal_error(true, "Adding archived host \"%s\" with GUID \"%s\" node id = \"%s\"", rrdhost_hostname(host), host->machine_guid, node_str);
160
+ internal_error(true, "Adding archived host \"%s\" with GUID \"%s\" node id = \"%s\" ephemeral=%d", rrdhost_hostname(host), host->machine_guid, node_str, is_ephemeral);
161
#endif
162
return 0;
163
}
@@ -215,6 +247,43 @@ fail:
247
buffer_free(sql);
248
}
249
250
+// OPCODE: ACLK_DATABASE_NODE_UNREGISTER
251
+static void sql_unregister_node(char *machine_guid)
252
+{
253
+ int rc;
254
+ uuid_t host_uuid;
255
+
256
+ if (unlikely(!machine_guid))
257
+ return;
258
+
259
+ rc = uuid_parse(machine_guid, host_uuid);
260
+ freez(machine_guid);
261
+ if (rc)
262
+ return;
263
+
264
+ sqlite3_stmt *res = NULL;
265
+
266
+ rc = sqlite3_prepare_v2(db_meta, "UPDATE node_instance SET node_id = NULL WHERE host_id = @host_id", -1, &res, 0);
267
+ if (unlikely(rc != SQLITE_OK)) {
268
+ error_report("Failed to prepare statement remote node id for a host");
269
+ return;
270
+ }
271
+
272
+ rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC);
273
+ if (unlikely(rc != SQLITE_OK)) {
274
+ error_report("Failed to bind host_id parameter to remove node id");
275
+ goto failed;
276
+ }
277
+ rc = sqlite3_step_monitored(res);
278
+ if (unlikely(rc != SQLITE_DONE))
279
+ error_report("Failed to execute command to remove node id");
280
+
281
+failed:
282
+ if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
283
+ error_report("Failed to finalize statement to remove node id");
284
+}
285
+
286
+
287
static int sql_check_aclk_table(void *data __maybe_unused, int argc __maybe_unused, char **argv __maybe_unused, char **column __maybe_unused)
288
{
289
struct aclk_database_cmd cmd;
@@ -375,7 +444,10 @@ static void aclk_synchronization(void *arg __maybe_unused)
444
struct aclk_sync_cfg_t *ahc = host->aclk_config;
445
if (unlikely(!ahc))
446
sql_create_aclk_table(host, &host->host_uuid, host->node_id);
378
- aclk_host_state_update(host, live);
447
+ aclk_host_state_update(host, live, 1);
448
+ break;
449
+ case ACLK_DATABASE_NODE_UNREGISTER:
450
+ sql_unregister_node(cmd.param[0]);
451
break;
452
// ALERTS
453
case ACLK_DATABASE_PUSH_ALERT_CONFIG:
@@ -472,7 +544,10 @@ void sql_create_aclk_table(RRDHOST *host __maybe_unused, uuid_t *host_uuid __may
544
#define SQL_FETCH_ALL_HOSTS \
545
"SELECT host_id, hostname, registry_hostname, update_every, os, " \
546
"timezone, tags, hops, memory_mode, abbrev_timezone, utc_offset, program_name, " \
475
- "program_version, entries, health_enabled, last_connected FROM host WHERE hops >0;"
547
+ "program_version, entries, health_enabled, last_connected, " \
548
+ "(SELECT CASE WHEN hl.label_value = 'true' THEN 1 ELSE 0 END FROM " \
549
+ "host_label hl WHERE hl.host_id = h.host_id AND hl.label_key = '_is_ephemeral') " \
550
+ "FROM host h WHERE hops > 0"
551
552
#define SQL_FETCH_ALL_INSTANCES \
553
"SELECT ni.host_id, ni.node_id FROM host h, node_instance ni " \
@@ -572,3 +647,18 @@ void schedule_node_info_update(RRDHOST *host __maybe_unused)
647
aclk_database_enq_cmd(&cmd);
648
#endif
649
}
650
+
651
+#ifdef ENABLE_ACLK
652
+void unregister_node(const char *machine_guid)
653
+{
654
+ if (unlikely(!machine_guid))
655
+ return;
656
+
657
+ struct aclk_database_cmd cmd;
658
+ memset(&cmd, 0, sizeof(cmd));
659
+ cmd.opcode = ACLK_DATABASE_NODE_UNREGISTER;
660
+ cmd.param[0] = strdupz(machine_guid);
661
+ cmd.completion = NULL;
662
+ aclk_database_enq_cmd(&cmd);
663
+}
664
+#endif
\ No newline at end of file
database/sqlite/sqlite_aclk.h
+4
@@ -59,6 +59,7 @@ enum aclk_database_opcode {
59
ACLK_DATABASE_PUSH_ALERT_SNAPSHOT,
60
ACLK_DATABASE_PUSH_ALERT_CHECKPOINT,
61
ACLK_DATABASE_QUEUE_REMOVED_ALERTS,
62
+ ACLK_DATABASE_NODE_UNREGISTER,
63
ACLK_DATABASE_TIMER,
64
65
// leave this last
@@ -93,5 +94,8 @@ void aclk_push_alert_config(const char *node_id, const char *config_hash);
94
void aclk_push_node_alert_snapshot(const char *node_id);
95
void aclk_push_node_removed_alerts(const char *node_id);
96
void schedule_node_info_update(RRDHOST *host);
97
+#ifdef ENABLE_ACLK
98
+void unregister_node(const char *machine_guid);
99
+#endif
100
101
#endif //NETDATA_SQLITE_ACLK_H
health/health.c
-14
@@ -1651,17 +1651,3 @@ void *health_main(void *ptr) {
1651
netdata_thread_cleanup_pop(1);
1652
return NULL;
1653
}
1654
-
1655
-void health_add_host_labels(void) {
1656
- RRDLABELS *labels = localhost->rrdlabels;
1657
-
1658
- // The source should be CONF, but when it is set, these labels are exported by default ('send configured labels' in exporting.conf).
1659
- // Their export seems to break exporting to Graphite, see https://github.com/netdata/netdata/issues/14084.
1660
-
1661
- int is_ephemeral = appconfig_get_boolean(&netdata_config, CONFIG_SECTION_HEALTH, "is ephemeral", CONFIG_BOOLEAN_NO);
1662
- rrdlabels_add(labels, "_is_ephemeral", is_ephemeral ? "true" : "false", RRDLABEL_SRC_AUTO);
1663
-
1664
- int has_unstable_connection = appconfig_get_boolean(&netdata_config, CONFIG_SECTION_HEALTH, "has unstable connection", CONFIG_BOOLEAN_NO);
1665
- rrdlabels_add(labels, "_has_unstable_connection", has_unstable_connection ? "true" : "false", RRDLABEL_SRC_AUTO);
1666
-}
1667
-
health/health.h
-1
@@ -102,7 +102,6 @@ void *health_cmdapi_thread(void *ptr);
102
char *health_edit_command_from_source(const char *source);
103
void sql_refresh_hashes(void);
104
105
-void health_add_host_labels(void);
105
void health_string2json(BUFFER *wb, const char *prefix, const char *label, const char *value, const char *suffix);
106
107
void health_log_alert_transition_with_trace(RRDHOST *host, ALARM_ENTRY *ae, int line, const char *file, const char *function);
streaming/receiver.c
+34
-26
@@ -623,6 +623,10 @@ static void rrdpush_receive(struct receiver_state *rpt)
623
rpt->config.rrdpush_compression = appconfig_get_boolean(&stream_config, rpt->key, "enable compression", rpt->config.rrdpush_compression);
624
rpt->config.rrdpush_compression = appconfig_get_boolean(&stream_config, rpt->machine_guid, "enable compression", rpt->config.rrdpush_compression);
625
626
+ bool is_ephemeral = false;
627
+ is_ephemeral = appconfig_get_boolean(&stream_config, rpt->key, "is ephemeral node", CONFIG_BOOLEAN_NO);
628
+ is_ephemeral = appconfig_get_boolean(&stream_config, rpt->machine_guid, "is ephemeral node", is_ephemeral);
629
+
630
if(rpt->config.rrdpush_compression) {
631
char *order = appconfig_get(&stream_config, rpt->key, "compression algorithms order", RRDPUSH_COMPRESSION_ALGORITHMS_ORDER);
632
order = appconfig_get(&stream_config, rpt->machine_guid, "compression algorithms order", order);
@@ -635,30 +639,31 @@ static void rrdpush_receive(struct receiver_state *rpt)
639
{
640
// this will also update the host with our system_info
641
RRDHOST *host = rrdhost_find_or_create(
638
- rpt->hostname
639
- , rpt->registry_hostname
640
- , rpt->machine_guid
641
- , rpt->os
642
- , rpt->timezone
643
- , rpt->abbrev_timezone
644
- , rpt->utc_offset
645
- , rpt->tags
646
- , rpt->program_name
647
- , rpt->program_version
648
- , rpt->config.update_every
649
- , rpt->config.history
650
- , rpt->config.mode
651
- , (unsigned int)(rpt->config.health_enabled != CONFIG_BOOLEAN_NO)
652
- , (unsigned int)(rpt->config.rrdpush_enabled && rpt->config.rrdpush_destination && *rpt->config.rrdpush_destination && rpt->config.rrdpush_api_key && *rpt->config.rrdpush_api_key)
653
- , rpt->config.rrdpush_destination
654
- , rpt->config.rrdpush_api_key
655
- , rpt->config.rrdpush_send_charts_matching
656
- , rpt->config.rrdpush_enable_replication
657
- , rpt->config.rrdpush_seconds_to_replicate
658
- , rpt->config.rrdpush_replication_step
659
- , rpt->system_info
660
- , 0
661
- );
642
+ rpt->hostname,
643
+ rpt->registry_hostname,
644
+ rpt->machine_guid,
645
+ rpt->os,
646
+ rpt->timezone,
647
+ rpt->abbrev_timezone,
648
+ rpt->utc_offset,
649
+ rpt->tags,
650
+ rpt->program_name,
651
+ rpt->program_version,
652
+ rpt->config.update_every,
653
+ rpt->config.history,
654
+ rpt->config.mode,
655
+ (unsigned int)(rpt->config.health_enabled != CONFIG_BOOLEAN_NO),
656
+ (unsigned int)(rpt->config.rrdpush_enabled && rpt->config.rrdpush_destination &&
657
+ *rpt->config.rrdpush_destination && rpt->config.rrdpush_api_key &&
658
+ *rpt->config.rrdpush_api_key),
659
+ rpt->config.rrdpush_destination,
660
+ rpt->config.rrdpush_api_key,
661
+ rpt->config.rrdpush_send_charts_matching,
662
+ rpt->config.rrdpush_enable_replication,
663
+ rpt->config.rrdpush_seconds_to_replicate,
664
+ rpt->config.rrdpush_replication_step,
665
+ rpt->system_info,
666
+ 0);
667
668
if(!host) {
669
rrdpush_receive_log_status(
@@ -807,11 +812,14 @@ static void rrdpush_receive(struct receiver_state *rpt)
812
// in case we have cloud connection we inform cloud
813
// new child connected
814
if (netdata_cloud_enabled)
810
- aclk_host_state_update(rpt->host, 1);
815
+ aclk_host_state_update(rpt->host, 1, 1);
816
#endif
817
818
rrdhost_set_is_parent_label();
819
820
+ if (is_ephemeral)
821
+ rrdhost_option_set(rpt->host, RRDHOST_OPTION_EPHEMERAL_HOST);
822
+
823
// let it reconnect to parent immediately
824
rrdpush_reset_destinations_postpone_time(rpt->host);
825
@@ -837,7 +845,7 @@ static void rrdpush_receive(struct receiver_state *rpt)
845
// in case we have cloud connection we inform cloud
846
// a child disconnected
847
if (netdata_cloud_enabled)
840
- aclk_host_state_update(rpt->host, 0);
848
+ aclk_host_state_update(rpt->host, 0, 1);
849
#endif
850
851
cleanup:
streaming/stream.conf
+10
@@ -183,6 +183,11 @@
183
# The duration we want to replicate per each step.
184
#replication_step = 600
185
186
+ # Indicate whether this child is an ephemeral node. An ephemeral node will become unavailable
187
+ # after the specified duration of "cleanup ephemeral hosts after secs" (as defined in the db section of netdata.conf)
188
+ # from the time of the node's last connection.
189
+ #is ephemeral node = false
190
+
191
# -----------------------------------------------------------------------------
192
# 3. PER SENDING HOST SETTINGS, ON PARENT NETDATA
193
# THIS IS OPTIONAL - YOU DON'T HAVE TO CONFIGURE IT
@@ -253,3 +258,8 @@
258
259
# The duration we want to replicate per each step.
260
#replication_step = 600
261
+
262
+ # Indicate whether this child is an ephemeral node. An ephemeral node will become unavailable
263
+ # after the specified duration of "cleanup ephemeral hosts after secs" (as defined in the db section of netdata.conf)
264
+ # from the time of the node's last connection.
265
+ #is ephemeral node = false