diff --git a/include/crm/common/alerts_internal.h b/include/crm/common/alerts_internal.h index c3c39c2375..c7209f5fd1 100644 --- a/include/crm/common/alerts_internal.h +++ b/include/crm/common/alerts_internal.h @@ -1,112 +1,115 @@ /* * Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ALERT_INTERNAL_H #define ALERT_INTERNAL_H + +#include <glib.h> + /* Default-Timeout to use before killing a alerts script (in milliseconds) */ # define CRM_ALERT_DEFAULT_TIMEOUT_MS (30000) /* Default-Format-String used to pass timestamps to the alerts scripts */ # define CRM_ALERT_DEFAULT_TSTAMP_FORMAT "%H:%M:%S.%06N" typedef struct { char *name; char *value; } crm_alert_envvar_t; enum crm_alert_flags { crm_alert_none = 0x0000, crm_alert_node = 0x0001, crm_alert_fencing = 0x0002, crm_alert_resource = 0x0004, crm_alert_attribute = 0x0008, crm_alert_default = crm_alert_node|crm_alert_fencing|crm_alert_resource }; typedef struct { char *id; char *path; char *tstamp_format; char *recipient; char **select_attribute_name; - GListPtr envvars; + GHashTable *envvars; int timeout; uint32_t flags; } crm_alert_entry_t; enum crm_alert_keys_e { CRM_alert_recipient = 0, CRM_alert_node, CRM_alert_nodeid, CRM_alert_rsc, CRM_alert_task, CRM_alert_interval, CRM_alert_desc, CRM_alert_status, CRM_alert_target_rc, CRM_alert_rc, CRM_alert_kind, CRM_alert_version, CRM_alert_node_sequence, CRM_alert_timestamp, CRM_alert_attribute_name, CRM_alert_attribute_value, CRM_alert_select_kind, CRM_alert_select_attribute_name }; #define CRM_ALERT_INTERNAL_KEY_MAX 16 #define CRM_ALERT_KEY_PATH "CRM_alert_path" #define CRM_ALERT_NODE_SEQUENCE "CRM_alert_node_sequence" extern guint crm_alert_max_alert_timeout; extern const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3]; crm_alert_entry_t *crm_dup_alert_entry(crm_alert_entry_t *entry); crm_alert_envvar_t *crm_dup_alert_envvar(crm_alert_envvar_t *src); +crm_alert_entry_t *crm_alert_entry_new(const char *id, const char *path); void crm_free_alert_entry(crm_alert_entry_t *entry); void crm_free_alert_envvar(crm_alert_envvar_t *entry); void crm_set_alert_key(enum crm_alert_keys_e name, const char *value); void crm_set_alert_key_int(enum crm_alert_keys_e name, int value); void crm_insert_alert_key(GHashTable *table, enum crm_alert_keys_e name, const char *value); void crm_insert_alert_key_int(GHashTable *table, enum crm_alert_keys_e name, int value); void crm_unset_alert_keys(void); void crm_set_envvar_list(crm_alert_entry_t *entry); void crm_unset_envvar_list(crm_alert_entry_t *entry); gboolean crm_is_target_alert(char **list, const char *value); static inline const char * crm_alert_flag2text(enum crm_alert_flags flag) { switch (flag) { case crm_alert_node: return "node"; case crm_alert_fencing: return "fencing"; case crm_alert_resource: return "resource"; case crm_alert_attribute: return "attribute"; default: return "unknown"; } } - #endif diff --git a/lib/common/alerts.c b/lib/common/alerts.c index 44130c2071..051d9f7249 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -1,259 +1,255 @@ /* * Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <crm_internal.h> #include <crm/crm.h> #include <crm/lrmd.h> #include <crm/msg_xml.h> #include <crm/common/alerts_internal.h> guint crm_alert_max_alert_timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; /* * to allow script compatibility we can have more than one * set of environment variables */ const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3] = { [CRM_alert_recipient] = {"CRM_notify_recipient", "CRM_alert_recipient", NULL}, [CRM_alert_node] = {"CRM_notify_node", "CRM_alert_node", NULL}, [CRM_alert_nodeid] = {"CRM_notify_nodeid", "CRM_alert_nodeid", NULL}, [CRM_alert_rsc] = {"CRM_notify_rsc", "CRM_alert_rsc", NULL}, [CRM_alert_task] = {"CRM_notify_task", "CRM_alert_task", NULL}, [CRM_alert_interval] = {"CRM_notify_interval", "CRM_alert_interval", NULL}, [CRM_alert_desc] = {"CRM_notify_desc", "CRM_alert_desc", NULL}, [CRM_alert_status] = {"CRM_notify_status", "CRM_alert_status", NULL}, [CRM_alert_target_rc] = {"CRM_notify_target_rc", "CRM_alert_target_rc", NULL}, [CRM_alert_rc] = {"CRM_notify_rc", "CRM_alert_rc", NULL}, [CRM_alert_kind] = {"CRM_notify_kind", "CRM_alert_kind", NULL}, [CRM_alert_version] = {"CRM_notify_version", "CRM_alert_version", NULL}, [CRM_alert_node_sequence] = {"CRM_notify_node_sequence", CRM_ALERT_NODE_SEQUENCE, NULL}, [CRM_alert_timestamp] = {"CRM_notify_timestamp", "CRM_alert_timestamp", NULL}, [CRM_alert_attribute_name] = {"CRM_notify_attribute_name", "CRM_alert_attribute_name", NULL}, [CRM_alert_attribute_value] = {"CRM_notify_attribute_value", "CRM_alert_attribute_value", NULL} }; void crm_free_alert_envvar(crm_alert_envvar_t *entry) { free(entry->name); free(entry->value); free(entry); } +/*! + * \brief Create a new alert entry structure + * + * \param[in] id ID to use + * \param[in] path Path to alert agent executable + * + * \return Pointer to newly allocated alert entry + * \note Non-string fields will be filled in with defaults. + * It is the caller's responsibility to free the result, + * using crm_free_alert_entry(). + */ +crm_alert_entry_t * +crm_alert_entry_new(const char *id, const char *path) +{ + crm_alert_entry_t *entry = calloc(1, sizeof(crm_alert_entry_t)); + + CRM_ASSERT(entry); + entry->id = strdup(id); + entry->path = strdup(path); + entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; + entry->flags = crm_alert_default; + return entry; +} + void crm_free_alert_entry(crm_alert_entry_t *entry) { free(entry->id); free(entry->path); free(entry->tstamp_format); free(entry->recipient); if(entry->select_attribute_name) { g_strfreev(entry->select_attribute_name); } if (entry->envvars) { - g_list_free_full(entry->envvars, - (GDestroyNotify) crm_free_alert_envvar); + g_hash_table_destroy(entry->envvars); } free(entry); } crm_alert_envvar_t * crm_dup_alert_envvar(crm_alert_envvar_t *src) { crm_alert_envvar_t *dst = calloc(1, sizeof(crm_alert_envvar_t)); CRM_ASSERT(dst); dst->name = strdup(src->name); dst->value = src->value?strdup(src->value):NULL; return dst; } -static GListPtr -copy_envvar_list_remove_dupes(crm_alert_entry_t *entry) -{ - GListPtr dst = NULL, ls, ld; - - /* we are adding to the front so variable dupes coming via - * recipient-section have got precedence over those in the - * global section - we don't expect that many variables here - * that it pays off to go for a hash-table to make dupe elimination - * more efficient - maybe later when we might decide to do more - * with the variables than cycling through them - */ - - for (ls = g_list_first(entry->envvars); ls; ls = g_list_next(ls)) { - for (ld = g_list_first(dst); ld; ld = g_list_next(ld)) { - if (!strcmp(((crm_alert_envvar_t *)(ls->data))->name, - ((crm_alert_envvar_t *)(ld->data))->name)) { - break; - } - } - if (!ld) { - dst = g_list_prepend(dst, crm_dup_alert_envvar((crm_alert_envvar_t *)(ls->data))); - } - } - - return dst; -} - /*! * \internal * \brief Duplicate an alert entry * * \param[in] entry Alert entry to duplicate * * \return Duplicate of alert entry */ crm_alert_entry_t * crm_dup_alert_entry(crm_alert_entry_t *entry) -{ - crm_alert_entry_t *new_entry = - (crm_alert_entry_t *) calloc(1, sizeof(crm_alert_entry_t)); +{ + crm_alert_entry_t *new_entry = crm_alert_entry_new(entry->id, entry->path); - CRM_ASSERT(new_entry); - *new_entry = (crm_alert_entry_t) { - .id = strdup(entry->id), - .path = strdup(entry->path), - .timeout = entry->timeout, - .tstamp_format = entry->tstamp_format?strdup(entry->tstamp_format):NULL, - .recipient = entry->recipient?strdup(entry->recipient):NULL, - .flags = entry->flags, - .select_attribute_name = entry->select_attribute_name?g_strdupv(entry->select_attribute_name):NULL, - .envvars = entry->envvars? - copy_envvar_list_remove_dupes(entry) - :NULL - }; + new_entry->timeout = entry->timeout; + new_entry->flags = entry->flags; + new_entry->envvars = crm_str_table_dup(entry->envvars); + if (entry->tstamp_format) { + new_entry->tstamp_format = strdup(entry->tstamp_format); + } + if (entry->recipient) { + new_entry->recipient = strdup(entry->recipient); + } + if (entry->select_attribute_name) { + new_entry->select_attribute_name = g_strdupv(entry->select_attribute_name); + } return new_entry; -} +} void crm_set_alert_key(enum crm_alert_keys_e name, const char *value) { const char **key; for (key = crm_alert_keys[name]; *key; key++) { crm_trace("Setting alert key %s = '%s'", *key, value); if (value) { setenv(*key, value, 1); } else { unsetenv(*key); } } } void crm_set_alert_key_int(enum crm_alert_keys_e name, int value) { char *s = crm_itoa(value); crm_set_alert_key(name, s); free(s); } void crm_unset_alert_keys() { const char **key; enum crm_alert_keys_e name; for(name = 0; name < DIMOF(crm_alert_keys); name++) { for(key = crm_alert_keys[name]; *key; key++) { crm_trace("Unsetting alert key %s", *key); unsetenv(*key); } } } void crm_insert_alert_key(GHashTable *table, enum crm_alert_keys_e name, const char *value) { for (const char **key = crm_alert_keys[name]; *key; key++) { crm_trace("Inserting alert key %s = '%s'", *key, value); if (value) { g_hash_table_insert(table, strdup(*key), strdup(value)); } else { g_hash_table_remove(table, *key); } } } void crm_insert_alert_key_int(GHashTable *table, enum crm_alert_keys_e name, int value) { for (const char **key = crm_alert_keys[name]; *key; key++) { crm_trace("Inserting alert key %s = %d", *key, value); g_hash_table_insert(table, strdup(*key), crm_itoa(value)); } } +static void +set_envvar(gpointer key, gpointer value, gpointer user_data) +{ + gboolean always_unset = GPOINTER_TO_INT(user_data); + + crm_trace("%s environment variable %s='%s'", + (value? "Setting" : "Unsetting"), + (char*)key, (value? (char*)value : "")); + if (value && !always_unset) { + setenv(key, value, 1); + } else { + unsetenv(key); + } +} + void crm_set_envvar_list(crm_alert_entry_t *entry) { - GListPtr l; - - for (l = g_list_first(entry->envvars); l; l = g_list_next(l)) { - crm_alert_envvar_t *env = (crm_alert_envvar_t *)(l->data); - - crm_trace("Setting environment variable %s = '%s'", env->name, - env->value?env->value:""); - if (env->value) { - setenv(env->name, env->value, 1); - } else { - unsetenv(env->name); - } + if (entry->envvars) { + g_hash_table_foreach(entry->envvars, set_envvar, GINT_TO_POINTER(FALSE)); } } +/* + * \note We have no way of restoring a previous value if one was set. + */ void crm_unset_envvar_list(crm_alert_entry_t *entry) { - GListPtr l; - - for (l = g_list_first(entry->envvars); l; l = g_list_next(l)) { - crm_alert_envvar_t *env = (crm_alert_envvar_t *)(l->data); - - crm_trace("Unsetting environment variable %s", env->name); - unsetenv(env->name); + if (entry->envvars) { + g_hash_table_foreach(entry->envvars, set_envvar, GINT_TO_POINTER(TRUE)); } } gboolean crm_is_target_alert(char **list, const char *value) { int target_list_num = 0; gboolean rc = FALSE; if (list == NULL) return TRUE; target_list_num = g_strv_length(list); for( int cnt = 0; cnt < target_list_num; cnt++ ) { if (strcmp(list[cnt], value) == 0) { rc = TRUE; break; } } return rc; } diff --git a/lib/lrmd/lrmd_alerts.c b/lib/lrmd/lrmd_alerts.c index e6c5c503a8..840492f99d 100644 --- a/lib/lrmd/lrmd_alerts.c +++ b/lib/lrmd/lrmd_alerts.c @@ -1,63 +1,68 @@ /* * Copyright (c) 2015 David Vossel <davidvossel@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include <crm_internal.h> #include <glib.h> #include <unistd.h> #include <crm/crm.h> #include <crm/msg_xml.h> #include <crm/services.h> #include <crm/common/mainloop.h> #include <crm/common/alerts_internal.h> #include <crm/lrmd_alerts_internal.h> #include <crm/pengine/status.h> #include <crm/cib.h> #include <crm/lrmd.h> lrmd_key_value_t * lrmd_set_alert_key_to_lrmd_params(lrmd_key_value_t *head, enum crm_alert_keys_e name, const char *value) { const char **key; for (key = crm_alert_keys[name]; *key; key++) { crm_trace("Setting alert key %s = '%s'", *key, value); head = lrmd_key_value_add(head, *key, value); } return head; } -lrmd_key_value_t * -lrmd_set_alert_envvar_to_lrmd_params(lrmd_key_value_t *head, crm_alert_entry_t *entry) +static void +set_ev_kv(gpointer key, gpointer value, gpointer user_data) { - GListPtr l; + lrmd_key_value_t **head = (lrmd_key_value_t **) user_data; - for (l = g_list_first(entry->envvars); l; l = g_list_next(l)) { - crm_alert_envvar_t *ev = (crm_alert_envvar_t *)(l->data); + if (value) { + crm_trace("Setting environment variable %s='%s'", + (char*)key, (char*)value); + *head = lrmd_key_value_add(*head, key, value); + } +} - if (ev->value) { - crm_trace("Setting environment variable %s='%s'", - ev->name, ev->value); - head = lrmd_key_value_add(head, ev->name, ev->value); - } +lrmd_key_value_t * +lrmd_set_alert_envvar_to_lrmd_params(lrmd_key_value_t *head, + crm_alert_entry_t *entry) +{ + if (entry->envvars) { + g_hash_table_foreach(entry->envvars, set_ev_kv, &head); } return head; } diff --git a/lib/pengine/rules_alerts.c b/lib/pengine/rules_alerts.c index 12686c193e..21fd50d615 100644 --- a/lib/pengine/rules_alerts.c +++ b/lib/pengine/rules_alerts.c @@ -1,285 +1,253 @@ /* * Copyright (C) 2015-2017 Andrew Beekhof <andrew@beekhof.net> * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include <crm_internal.h> #include <crm/crm.h> #include <crm/msg_xml.h> #include <crm/pengine/rules.h> #include <crm/common/alerts_internal.h> #include <crm/pengine/rules_internal.h> #ifdef RHEL7_COMPAT /* @COMPAT An early implementation of alerts was backported to RHEL 7, * even though it was never in an upstream release. */ static char *notify_script = NULL; static char *notify_target = NULL; void pe_enable_legacy_alerts(const char *script, const char *target) { free(notify_script); notify_script = (script && strcmp(script, "/dev/null"))? strdup(script) : NULL; free(notify_target); notify_target = target? strdup(target): NULL; } #endif -static GHashTable * +static void get_meta_attrs_from_cib(xmlNode *basenode, crm_alert_entry_t *entry, guint *max_timeout) { GHashTable *config_hash = crm_str_table_new(); crm_time_t *now = crm_time_new(NULL); const char *value = NULL; unpack_instance_attributes(basenode, basenode, XML_TAG_META_SETS, NULL, config_hash, NULL, FALSE, now); + crm_time_free(now); value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TIMEOUT); if (value) { entry->timeout = crm_get_msec(value); if (entry->timeout <= 0) { if (entry->timeout == 0) { - crm_trace("Setting timeout to default %dmsec", - CRM_ALERT_DEFAULT_TIMEOUT_MS); + crm_trace("Alert %s uses default timeout of %dmsec", + entry->id, CRM_ALERT_DEFAULT_TIMEOUT_MS); } else { - crm_warn("Invalid timeout value setting to default %dmsec", - CRM_ALERT_DEFAULT_TIMEOUT_MS); + crm_warn("Alert %s has invalid timeout value '%s', using default %dmsec", + entry->id, (char*)value, CRM_ALERT_DEFAULT_TIMEOUT_MS); } entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; } else { - crm_trace("Found timeout %dmsec", entry->timeout); + crm_trace("Alert %s uses timeout of %dmsec", + entry->id, entry->timeout); } if (entry->timeout > *max_timeout) { *max_timeout = entry->timeout; } } value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TSTAMP_FORMAT); if (value) { /* hard to do any checks here as merely anything can * can be a valid time-format-string */ - entry->tstamp_format = (char *) value; - crm_trace("Found timestamp format string '%s'", value); + entry->tstamp_format = strdup(value); + crm_trace("Alert %s uses timestamp format '%s'", + entry->id, entry->tstamp_format); } value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_SELECT_KIND); if (value) { int n = 0; uint32_t flags = crm_alert_none; crm_debug("Alert %s has event filter: %s", entry->id, value); while (*value != 0) { while (*value == ',') { ++value; } n = 0; while ((value[n] != ',') && (value[n] != 0)) { ++n; } if (!strncmp(value, "node", n)) { flags |= crm_alert_node; } else if (!strncmp(value, "fencing", n)) { flags |= crm_alert_fencing; } else if (!strncmp(value, "resource", n)) { flags |= crm_alert_resource; } else if (!strncmp(value, "attribute", n)) { flags |= crm_alert_attribute; } else { crm_warn("Unrecognized alert type '%s' for %s", value, entry->id); } value += n; } if (flags) { entry->flags = flags; } } value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_SELECT_ATTRIBUTE_NAME); if (value) { crm_debug("Alert %s has attribute filter: %s", entry->id, value); - entry->select_attribute_name = g_strsplit((char*) value, ",", 0); - crm_trace("Found attribute_name string '%s'", (char *) value); + entry->select_attribute_name = g_strsplit(value, ",", 0); } - crm_time_free(now); - return config_hash; /* keep hash as long as strings are needed */ + g_hash_table_destroy(config_hash); } static void -drop_envvars(crm_alert_entry_t *entry, int count) -{ - int i; - - for (i = 0; entry->envvars && ((count < 0) || (i < count)); i++) { - GListPtr first = g_list_first(entry->envvars); - - crm_free_alert_envvar((crm_alert_envvar_t *) first->data); - entry->envvars = g_list_delete_link(entry->envvars, first); - } -} - -static GListPtr -get_envvars_from_cib(xmlNode *basenode, crm_alert_entry_t *entry, int *count) +get_envvars_from_cib(xmlNode *basenode, crm_alert_entry_t *entry) { xmlNode *child; - if (basenode == NULL) { - return entry->envvars; + if ((basenode == NULL) || (entry == NULL)) { + return; } child = first_named_child(basenode, XML_TAG_ATTR_SETS); if (child == NULL) { - return entry->envvars; + return; + } + + if (entry->envvars == NULL) { + entry->envvars = crm_str_table_new(); } for (child = first_named_child(child, XML_CIB_TAG_NVPAIR); child != NULL; child = __xml_next(child)) { - crm_alert_envvar_t envvar_entry = (crm_alert_envvar_t) { - .name = (char *) crm_element_value(child, XML_NVPAIR_ATTR_NAME), - .value = (char *) crm_element_value(child, XML_NVPAIR_ATTR_VALUE) - }; - crm_trace("Found environment variable %s = '%s'", envvar_entry.name, - (envvar_entry.value? envvar_entry.value : "")); - (*count)++; - entry->envvars = g_list_prepend(entry->envvars, - crm_dup_alert_envvar(&envvar_entry)); + const char *name = crm_element_value(child, XML_NVPAIR_ATTR_NAME); + const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE); + + if (value == NULL) { + value = ""; + } + g_hash_table_insert(entry->envvars, strdup(name), strdup(value)); + crm_trace("Alert %s: added environment variable %s='%s'", + entry->id, name, value); } - return entry->envvars; } /*! * \internal * \brief Unpack a CIB alerts section * * \param[in] alerts XML of alerts section * * \return List of unpacked alert entries * * \note Unlike most unpack functions, this is not used by the pengine itself, * but is supplied for use by daemons that need to send alerts. */ GListPtr pe_unpack_alerts(xmlNode *alerts) { xmlNode *alert; - crm_alert_entry_t entry; + crm_alert_entry_t *entry; guint max_timeout = 0; GListPtr alert_list = NULL; crm_alert_max_alert_timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; if (alerts) { #ifdef RHEL7_COMPAT if (notify_script) { crm_warn("Ignoring deprecated notification configuration because alerts available"); } #endif } else { #ifdef RHEL7_COMPAT if (notify_script) { - entry = (crm_alert_entry_t) { - .id = (char *) "legacy_notification", - .path = notify_script, - .timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS, - .recipient = notify_target, - .flags = crm_alert_default, - .select_attribute_name = NULL - }; - alert_list = g_list_prepend(alert_list, - crm_dup_alert_entry(&entry)); + entry = crm_alert_entry_new("legacy_notification", notify_script); + entry->recipient = strdup(notify_target); + entry->tstamp_format = strdup(CRM_ALERT_DEFAULT_TSTAMP_FORMAT); + alert_list = g_list_prepend(alert_list, entry); crm_warn("Deprecated notification syntax in use (alerts syntax is preferable)"); } #endif return alert_list; } for (alert = first_named_child(alerts, XML_CIB_TAG_ALERT); alert; alert = __xml_next(alert)) { xmlNode *recipient; - int recipients = 0, envvars = 0; - GHashTable *config_hash = NULL; + int recipients = 0; - entry = (crm_alert_entry_t) { - .id = (char *) crm_element_value(alert, XML_ATTR_ID), - .path = (char *) crm_element_value(alert, XML_ALERT_ATTR_PATH), - .timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS, - .tstamp_format = (char *) CRM_ALERT_DEFAULT_TSTAMP_FORMAT, - .flags = crm_alert_default, - .select_attribute_name = NULL - }; + entry = crm_alert_entry_new(crm_element_value(alert, XML_ATTR_ID), + crm_element_value(alert, XML_ALERT_ATTR_PATH)); - get_envvars_from_cib(alert, &entry, &envvars); - config_hash = get_meta_attrs_from_cib(alert, &entry, &max_timeout); + get_envvars_from_cib(alert, entry); + get_meta_attrs_from_cib(alert, entry, &max_timeout); + if (entry->tstamp_format == NULL) { + entry->tstamp_format = strdup(CRM_ALERT_DEFAULT_TSTAMP_FORMAT); + } - crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %d vars", - entry.id, entry.path, entry.timeout, entry.tstamp_format, - envvars); + crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars", + entry->id, entry->path, entry->timeout, entry->tstamp_format, + (entry->envvars? g_hash_table_size(entry->envvars) : 0)); for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT); recipient != NULL; recipient = __xml_next(recipient)) { - int envvars_added = 0; + crm_alert_entry_t *recipient_entry = crm_dup_alert_entry(entry); - entry.recipient = (char *) crm_element_value(recipient, - XML_ALERT_ATTR_REC_VALUE); recipients++; - - get_envvars_from_cib(recipient, &entry, &envvars_added); - - { - crm_alert_entry_t recipient_entry = entry; - GHashTable *config_hash = get_meta_attrs_from_cib(recipient, - &recipient_entry, - &max_timeout); - - alert_list = g_list_prepend(alert_list, - crm_dup_alert_entry(&recipient_entry)); - crm_debug("Alert has recipient: id=%s, value=%s, " - "%d additional environment variables", - crm_element_value(recipient, XML_ATTR_ID), - recipient_entry.recipient, envvars_added); - g_hash_table_destroy(config_hash); - } - - drop_envvars(&entry, envvars_added); + recipient_entry->recipient = strdup(crm_element_value(recipient, + XML_ALERT_ATTR_REC_VALUE)); + get_envvars_from_cib(recipient, recipient_entry); + get_meta_attrs_from_cib(recipient, recipient_entry, &max_timeout); + + alert_list = g_list_prepend(alert_list, recipient_entry); + crm_debug("Alert %s has recipient %s with value %s and %d envvars", + entry->id, ID(recipient), recipient_entry->recipient, + (recipient_entry->envvars? + g_hash_table_size(recipient_entry->envvars) : 0)); } if (recipients == 0) { - alert_list = g_list_prepend(alert_list, - crm_dup_alert_entry(&entry)); + alert_list = g_list_prepend(alert_list, entry); + } else { + crm_free_alert_entry(entry); } - - drop_envvars(&entry, -1); - g_hash_table_destroy(config_hash); } if (max_timeout > 0) { crm_alert_max_alert_timeout = max_timeout; } return alert_list; } /*! * \internal * \brief Free an alert list generated by pe_unpack_alerts() * * \param[in] alert_list Alert list to free */ void pe_free_alert_list(GListPtr alert_list) { if (alert_list) { g_list_free_full(alert_list, (GDestroyNotify) crm_free_alert_entry); } }