// debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
RRDCALC *rc;
- for(rc = st->rrdhost->calculations; rc ; rc = rc->next) {
+ for(rc = st->rrdhost->alarms; rc ; rc = rc->next) {
if(rc->rrdset) continue;
if(rrdcalc_is_matching_this_rrdset(rc, st))
if(rc->rrdset_next)
rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
- if(st->calculations == rc)
- st->calculations = rc->rrdset_next;
+ if(st->alarms == rc)
+ st->alarms = rc->rrdset_next;
rc->rrdset_prev = rc->rrdset_next = NULL;
RRDCALC *rc;
// make sure it does not already exist
- for(rc = host->calculations; rc ; rc = rc->next) {
+ for(rc = host->alarms; rc ; rc = rc->next) {
if (rc->hash == hash && !strcmp(name, rc->name)) {
error("Health alarm '%s' already exists in host '%s'.", name, host->hostname);
return 1;
}
// link it to the host
- rc->next = host->calculations;
- host->calculations = rc;
+ rc->next = host->alarms;
+ host->alarms = rc;
// link it to its chart
RRDSET *st;
if(rc->rrdset) rrdsetcalc_unlink(rc);
// unlink it from RRDHOST
- if(rc == host->calculations)
- host->calculations = rc->next;
+ if(rc == host->alarms)
+ host->alarms = rc->next;
- else if(host->calculations) {
- RRDCALC *t, *last = host->calculations;
+ else if(host->alarms) {
+ RRDCALC *t, *last = host->alarms;
for(t = last->next; t && t != rc; last = t, t = t->next) ;
if(last && last->next == rc)
else
error("Cannot unlink unlink '%s.%s' from host '%s': This host does not have any calculations", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
- if(rc->warning) expression_free(rc->warning);
- if(rc->critical) expression_free(rc->critical);
+ expression_free(rc->calculation);
+ expression_free(rc->warning);
+ expression_free(rc->critical);
freez(rc->source);
freez(rc->name);
freez(rc->chart);
freez(rc->dimensions);
freez(rc->exec);
-
freez(rc);
}
}
}
- if(rt->warning) expression_free(rt->warning);
- if(rt->critical) expression_free(rt->critical);
+ expression_free(rt->calculation);
+ expression_free(rt->warning);
+ expression_free(rt->critical);
freez(rt->dimensions);
freez(rt->context);
return 1;
}
-static inline int rrdcalctemplate_add(RRDHOST *host, RRDCALCTEMPLATE *rt) {
+static inline int rrdcalctemplate_add_template_from_config(RRDHOST *host, RRDCALCTEMPLATE *rt) {
if(!rt->context) {
error("Health configuration for template '%s' does not have a context", rt->name);
return 0;
return 1;
}
-static inline int health_parse_time(char *string, int *result) {
+static inline int health_parse_duration(char *string, int *result) {
// make sure it is a number
if(!*string || !(isdigit(*string) || *string == '+' || *string == '-')) {
*result = 0;
return 1;
}
-static inline int health_parse_lookup(
+static inline int health_parse_db_lookup(
size_t line, const char *path, const char *file, char *string,
int *group_method, int *after, int *before, int *every,
uint32_t *options, char **dimensions
while(*s && !isspace(*s)) s++;
while(*s && isspace(*s)) *s++ = '\0';
- if(!health_parse_time(key, after)) {
+ if(!health_parse_duration(key, after)) {
error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' after group method",
line, path, file, key);
return 0;
while(*s && !isspace(*s)) s++;
while(*s && isspace(*s)) *s++ = '\0';
- if (!health_parse_time(value, before)) {
+ if (!health_parse_duration(value, before)) {
error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
line, path, file, value, key);
}
while(*s && !isspace(*s)) s++;
while(*s && isspace(*s)) *s++ = '\0';
- if (!health_parse_time(value, every)) {
+ if (!health_parse_duration(value, every)) {
error("Health configuration at line %zu of file '%s/%s': invalid duration '%s' for '%s' keyword",
line, path, file, value, key);
}
rrdcalc_free(&localhost, rc);
if(rt) {
- if (!rrdcalctemplate_add(&localhost, rt))
+ if (!rrdcalctemplate_add_template_from_config(&localhost, rt))
rrdcalctemplate_free(&localhost, rt);
rt = NULL;
}
rc = NULL;
}
- if(rt && !rrdcalctemplate_add(&localhost, rt))
+ if(rt && !rrdcalctemplate_add_template_from_config(&localhost, rt))
rrdcalctemplate_free(&localhost, rt);
rt = callocz(1, sizeof(RRDCALCTEMPLATE));
rc->hash_chart = simple_hash(rc->chart);
}
else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
- health_parse_lookup(line, path, filename, value, &rc->group, &rc->after, &rc->before, &rc->update_every,
- &rc->options, &rc->dimensions);
+ health_parse_db_lookup(line, path, filename, value, &rc->group, &rc->after, &rc->before,
+ &rc->update_every,
+ &rc->options, &rc->dimensions);
}
else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
- if(!health_parse_time(value, &rc->update_every))
+ if(!health_parse_duration(value, &rc->update_every))
info("Health configuration at line %zu of file '%s/%s' for alarm '%s' at key '%s' cannot parse duration: '%s'.",
line, path, filename, rc->name, key, value);
}
rt->hash_context = simple_hash(rt->context);
}
else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
- health_parse_lookup(line, path, filename, value, &rt->group, &rt->after, &rt->before, &rt->update_every,
- &rt->options, &rt->dimensions);
+ health_parse_db_lookup(line, path, filename, value, &rt->group, &rt->after, &rt->before,
+ &rt->update_every,
+ &rt->options, &rt->dimensions);
}
else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
- if(!health_parse_time(value, &rt->update_every))
+ if(!health_parse_duration(value, &rt->update_every))
info("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' cannot parse duration: '%s'.",
line, path, filename, rt->name, key, value);
}
if(rc && !rrdcalc_add_alarm_from_config(&localhost, rc))
rrdcalc_free(&localhost, rc);
- if(rt && !rrdcalctemplate_add(&localhost, rt))
+ if(rt && !rrdcalctemplate_add_template_from_config(&localhost, rt))
rrdcalctemplate_free(&localhost, rt);
fclose(fp);
closedir(dir);
}
+static inline char *health_config_dir(void) {
+ char buffer[FILENAME_MAX + 1];
+ snprintfz(buffer, FILENAME_MAX, "%s/health.d", config_get("global", "config directory", CONFIG_DIR));
+ return config_get("health", "health configuration directory", buffer);
+}
+
void health_init(void) {
debug(D_HEALTH, "Health configuration initializing");
- char *path;
-
if(!(health_enabled = config_get_boolean("health", "enabled", 1))) {
debug(D_HEALTH, "Health is disabled.");
return;
}
+ char *path = health_config_dir();
+
{
char buffer[FILENAME_MAX + 1];
- snprintfz(buffer, FILENAME_MAX, "%s/health.d", config_get("global", "config directory", CONFIG_DIR));
- path = config_get("health", "health configuration directory", buffer);
-
snprintfz(buffer, FILENAME_MAX, "%s/alarm.sh", config_get("global", "plugins directory", PLUGINS_DIR));
health_default_exec = config_get("health", "script to execute on alarm", buffer);
}
rrdhost_unlock(&localhost);
}
+// ----------------------------------------------------------------------------
+// re-load health configuration
+
+static inline void health_free_all_nolock(RRDHOST *host) {
+ while(host->templates)
+ rrdcalctemplate_free(host, host->templates);
+
+ while(host->alarms)
+ rrdcalc_free(host, host->alarms);
+}
+
+void health_reload(void) {
+ if(!health_enabled) {
+ error("Health reload is requested, but health is not enabled.");
+ return;
+ }
+
+ char *path = health_config_dir();
+
+ rrdhost_rwlock(&localhost);
+ health_free_all_nolock(&localhost);
+ rrdhost_unlock(&localhost);
+
+ rrdhost_rwlock(&localhost);
+ health_readdir(path);
+ rrdhost_unlock(&localhost);
+
+ RRDSET *st;
+ for(st = localhost.rrdset_root; st ; st = st->next) {
+ rrdhost_rwlock(&localhost);
+
+ rrdsetcalc_link_matching(st);
+ rrdcalctemplate_link_matching(st);
+
+ rrdhost_unlock(&localhost);
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// health main thread and friends
+
static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) {
if (unlikely(!rc->rrdset)) {
debug(D_HEALTH, "Health not running alarm '%s.%s'. It is not linked to a chart.", rc->chart?rc->chart:"NOCHART", rc->name);
rrdhost_rdlock(&localhost);
// the first loop is to lookup values from the db
- for (rc = localhost.calculations; rc; rc = rc->next) {
+ for (rc = localhost.alarms; rc; rc = rc->next) {
if (unlikely(!rrdcalc_isrunnable(rc, now, &next_run)))
continue;
if (runnable) {
rrdhost_rdlock(&localhost);
- for (rc = localhost.calculations; rc; rc = rc->next) {
+ for (rc = localhost.alarms; rc; rc = rc->next) {
if (unlikely(!rrdcalc_isrunnable(rc, now, &next_run)))
continue;
// this causes the threads to block signals.
sigset_t sigset;
sigfillset(&sigset);
-
- if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1) {
+ if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1)
error("Could not block signals for threads");
- }
// Catch signals which we want to use
struct sigaction sa;
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGINT);
- sigaddset(&sa.sa_mask, SIGTERM);
- sa.sa_handler = sig_handler_exit;
sa.sa_flags = 0;
- if(sigaction(SIGINT, &sa, NULL) == -1) {
+
+ // ingore all signals while we run in a signal handler
+ sigfillset(&sa.sa_mask);
+
+ // INFO: If we add signals here we have to unblock them
+ // at popen.c when running a external plugin.
+
+ // Ignore SIGPIPE completely.
+ sa.sa_handler = SIG_IGN;
+ if(sigaction(SIGPIPE, &sa, NULL) == -1)
+ error("Failed to change signal handler for SIGPIPE");
+
+ sa.sa_handler = sig_handler_exit;
+ if(sigaction(SIGINT, &sa, NULL) == -1)
error("Failed to change signal handler for SIGINT");
- }
- if(sigaction(SIGTERM, &sa, NULL) == -1) {
+
+ sa.sa_handler = sig_handler_exit;
+ if(sigaction(SIGTERM, &sa, NULL) == -1)
error("Failed to change signal handler for SIGTERM");
- }
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGHUP);
sa.sa_handler = sig_handler_logrotate;
- sa.sa_flags = 0;
- if(sigaction(SIGHUP, &sa, NULL) == -1) {
+ if(sigaction(SIGHUP, &sa, NULL) == -1)
error("Failed to change signal handler for SIGHUP");
- }
// save database on SIGUSR1
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGUSR1);
sa.sa_handler = sig_handler_save;
- if(sigaction(SIGUSR1, &sa, NULL) == -1) {
+ if(sigaction(SIGUSR1, &sa, NULL) == -1)
error("Failed to change signal handler for SIGUSR1");
- }
- // Ignore SIGPIPE completely.
- // INFO: If we add signals here we have to unblock them
- // at popen.c when running a external plugin.
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGPIPE);
- sa.sa_handler = SIG_IGN;
- if(sigaction(SIGPIPE, &sa, NULL) == -1) {
- error("Failed to change signal handler for SIGPIPE");
- }
+ // reload health configuration on SIGUSR2
+ sa.sa_handler = sig_handler_reload_health;
+ if(sigaction(SIGUSR2, &sa, NULL) == -1)
+ error("Failed to change signal handler for SIGUSR2");
// --------------------------------------------------------------------