diff options
Diffstat (limited to 'lib/common/alerts.c')
-rw-r--r-- | lib/common/alerts.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/lib/common/alerts.c b/lib/common/alerts.c new file mode 100644 index 0000000..abdadef --- /dev/null +++ b/lib/common/alerts.c @@ -0,0 +1,253 @@ +/* + * Copyright 2015-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * 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/lrmd.h> +#include <crm/msg_xml.h> +#include <crm/common/alerts_internal.h> +#include <crm/common/xml_internal.h> +#include <crm/cib/internal.h> /* for F_CIB_UPDATE_RESULT */ + +/* + * to allow script compatibility we can have more than one + * set of environment variables + */ +const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX][3] = +{ + [PCMK__alert_key_recipient] = { + "CRM_notify_recipient", "CRM_alert_recipient", NULL + }, + [PCMK__alert_key_node] = { + "CRM_notify_node", "CRM_alert_node", NULL + }, + [PCMK__alert_key_nodeid] = { + "CRM_notify_nodeid", "CRM_alert_nodeid", NULL + }, + [PCMK__alert_key_rsc] = { + "CRM_notify_rsc", "CRM_alert_rsc", NULL + }, + [PCMK__alert_key_task] = { + "CRM_notify_task", "CRM_alert_task", NULL + }, + [PCMK__alert_key_interval] = { + "CRM_notify_interval", "CRM_alert_interval", NULL + }, + [PCMK__alert_key_desc] = { + "CRM_notify_desc", "CRM_alert_desc", NULL + }, + [PCMK__alert_key_status] = { + "CRM_notify_status", "CRM_alert_status", NULL + }, + [PCMK__alert_key_target_rc] = { + "CRM_notify_target_rc", "CRM_alert_target_rc", NULL + }, + [PCMK__alert_key_rc] = { + "CRM_notify_rc", "CRM_alert_rc", NULL + }, + [PCMK__alert_key_kind] = { + "CRM_notify_kind", "CRM_alert_kind", NULL + }, + [PCMK__alert_key_version] = { + "CRM_notify_version", "CRM_alert_version", NULL + }, + [PCMK__alert_key_node_sequence] = { + "CRM_notify_node_sequence", PCMK__ALERT_NODE_SEQUENCE, NULL + }, + [PCMK__alert_key_timestamp] = { + "CRM_notify_timestamp", "CRM_alert_timestamp", NULL + }, + [PCMK__alert_key_attribute_name] = { + "CRM_notify_attribute_name", "CRM_alert_attribute_name", NULL + }, + [PCMK__alert_key_attribute_value] = { + "CRM_notify_attribute_value", "CRM_alert_attribute_value", NULL + }, + [PCMK__alert_key_timestamp_epoch] = { + "CRM_notify_timestamp_epoch", "CRM_alert_timestamp_epoch", NULL + }, + [PCMK__alert_key_timestamp_usec] = { + "CRM_notify_timestamp_usec", "CRM_alert_timestamp_usec", NULL + }, + [PCMK__alert_key_exec_time] = { + "CRM_notify_exec_time", "CRM_alert_exec_time", NULL + } +}; + +/*! + * \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 pcmk__free_alert(). + */ +pcmk__alert_t * +pcmk__alert_new(const char *id, const char *path) +{ + pcmk__alert_t *entry = calloc(1, sizeof(pcmk__alert_t)); + + CRM_ASSERT(entry && id && path); + entry->id = strdup(id); + entry->path = strdup(path); + entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS; + entry->flags = pcmk__alert_default; + return entry; +} + +void +pcmk__free_alert(pcmk__alert_t *entry) +{ + if (entry) { + free(entry->id); + free(entry->path); + free(entry->tstamp_format); + free(entry->recipient); + + g_strfreev(entry->select_attribute_name); + if (entry->envvars) { + g_hash_table_destroy(entry->envvars); + } + free(entry); + } +} + +/*! + * \internal + * \brief Duplicate an alert entry + * + * \param[in] entry Alert entry to duplicate + * + * \return Duplicate of alert entry + */ +pcmk__alert_t * +pcmk__dup_alert(const pcmk__alert_t *entry) +{ + pcmk__alert_t *new_entry = pcmk__alert_new(entry->id, entry->path); + + new_entry->timeout = entry->timeout; + new_entry->flags = entry->flags; + new_entry->envvars = pcmk__str_table_dup(entry->envvars); + pcmk__str_update(&new_entry->tstamp_format, entry->tstamp_format); + pcmk__str_update(&new_entry->recipient, entry->recipient); + if (entry->select_attribute_name) { + new_entry->select_attribute_name = g_strdupv(entry->select_attribute_name); + } + return new_entry; +} + +void +pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name, + const char *value) +{ + for (const char **key = pcmk__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 +pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name, + int value) +{ + for (const char **key = pcmk__alert_keys[name]; *key; key++) { + crm_trace("Inserting alert key %s = %d", *key, value); + g_hash_table_insert(table, strdup(*key), pcmk__itoa(value)); + } +} + +#define XPATH_PATCHSET1_DIFF "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED + +#define XPATH_PATCHSET1_CRMCONFIG XPATH_PATCHSET1_DIFF "//" XML_CIB_TAG_CRMCONFIG +#define XPATH_PATCHSET1_ALERTS XPATH_PATCHSET1_DIFF "//" XML_CIB_TAG_ALERTS + +#define XPATH_PATCHSET1_EITHER \ + XPATH_PATCHSET1_CRMCONFIG " | " XPATH_PATCHSET1_ALERTS + +#define XPATH_CONFIG "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION + +#define XPATH_CRMCONFIG XPATH_CONFIG "/" XML_CIB_TAG_CRMCONFIG "/" +#define XPATH_ALERTS XPATH_CONFIG "/" XML_CIB_TAG_ALERTS + +/*! + * \internal + * \brief Check whether a CIB update affects alerts + * + * \param[in] msg XML containing CIB update + * \param[in] config Whether to check for crmconfig change as well + * + * \return TRUE if update affects alerts, FALSE otherwise + */ +bool +pcmk__alert_in_patchset(xmlNode *msg, bool config) +{ + int rc = -1; + int format= 1; + xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT); + xmlNode *change = NULL; + xmlXPathObject *xpathObj = NULL; + + CRM_CHECK(msg != NULL, return FALSE); + + crm_element_value_int(msg, F_CIB_RC, &rc); + if (rc < pcmk_ok) { + crm_trace("Ignore failed CIB update: %s (%d)", pcmk_strerror(rc), rc); + return FALSE; + } + + crm_element_value_int(patchset, "format", &format); + if (format == 1) { + const char *diff = (config? XPATH_PATCHSET1_EITHER : XPATH_PATCHSET1_ALERTS); + + if ((xpathObj = xpath_search(msg, diff)) != NULL) { + freeXpathObject(xpathObj); + return TRUE; + } + } else if (format == 2) { + for (change = pcmk__xml_first_child(patchset); change != NULL; + change = pcmk__xml_next(change)) { + const char *xpath = crm_element_value(change, XML_DIFF_PATH); + + if (xpath == NULL) { + continue; + } + + if ((!config || !strstr(xpath, XPATH_CRMCONFIG)) + && !strstr(xpath, XPATH_ALERTS)) { + + /* this is not a change to an existing section ... */ + + xmlNode *section = NULL; + const char *name = NULL; + + if ((strcmp(xpath, XPATH_CONFIG) != 0) || + ((section = pcmk__xml_first_child(change)) == NULL) || + ((name = crm_element_name(section)) == NULL) || + (strcmp(name, XML_CIB_TAG_ALERTS) != 0)) { + + /* ... nor is it a newly added alerts section */ + continue; + } + } + + return TRUE; + } + + } else { + crm_warn("Unknown patch format: %d", format); + } + return FALSE; +} |