Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4639913
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/common/alerts.c b/lib/common/alerts.c
index 1835d3c172..7cbd0fe741 100644
--- a/lib/common/alerts.c
+++ b/lib/common/alerts.c
@@ -1,435 +1,442 @@
/*
* Copyright 2015-2024 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/common/xml.h>
#include <crm/common/alerts_internal.h>
#include <crm/common/cib_internal.h>
#include <crm/common/xml_internal.h>
const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX] = {
[PCMK__alert_key_recipient] = "CRM_alert_recipient",
[PCMK__alert_key_node] = "CRM_alert_node",
[PCMK__alert_key_nodeid] = "CRM_alert_nodeid",
[PCMK__alert_key_rsc] = "CRM_alert_rsc",
[PCMK__alert_key_task] = "CRM_alert_task",
[PCMK__alert_key_interval] = "CRM_alert_interval",
[PCMK__alert_key_desc] = "CRM_alert_desc",
[PCMK__alert_key_status] = "CRM_alert_status",
[PCMK__alert_key_target_rc] = "CRM_alert_target_rc",
[PCMK__alert_key_rc] = "CRM_alert_rc",
[PCMK__alert_key_kind] = "CRM_alert_kind",
[PCMK__alert_key_version] = "CRM_alert_version",
[PCMK__alert_key_node_sequence] = PCMK__ALERT_NODE_SEQUENCE,
[PCMK__alert_key_timestamp] = "CRM_alert_timestamp",
[PCMK__alert_key_attribute_name] = "CRM_alert_attribute_name",
[PCMK__alert_key_attribute_value] = "CRM_alert_attribute_value",
[PCMK__alert_key_timestamp_epoch] = "CRM_alert_timestamp_epoch",
[PCMK__alert_key_timestamp_usec] = "CRM_alert_timestamp_usec",
[PCMK__alert_key_exec_time] = "CRM_alert_exec_time",
};
/*!
* \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 = pcmk__assert_alloc(1, sizeof(pcmk__alert_t));
pcmk__assert((id != NULL) && (path != NULL));
entry->id = pcmk__str_copy(id);
entry->path = pcmk__str_copy(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);
new_entry->tstamp_format = pcmk__str_copy(entry->tstamp_format);
new_entry->recipient = pcmk__str_copy(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)
{
pcmk__assert((table != NULL) && (name >= 0)
&& (name < PCMK__ALERT_INTERNAL_KEY_MAX));
if (value == NULL) {
crm_trace("Removing alert key %s", pcmk__alert_keys[name]);
g_hash_table_remove(table, pcmk__alert_keys[name]);
} else {
crm_trace("Inserting alert key %s = '%s'",
pcmk__alert_keys[name], value);
pcmk__insert_dup(table, pcmk__alert_keys[name], value);
}
}
void
pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name,
int value)
{
pcmk__assert((table != NULL) && (name >= 0)
&& (name < PCMK__ALERT_INTERNAL_KEY_MAX));
crm_trace("Inserting alert key %s = %d", pcmk__alert_keys[name], value);
g_hash_table_insert(table, pcmk__str_copy(pcmk__alert_keys[name]),
pcmk__itoa(value));
}
#define READABLE_DEFAULT pcmk__readable_interval(PCMK__ALERT_DEFAULT_TIMEOUT_MS)
/*!
* \internal
* \brief Unpack options for an alert or alert recipient from its
* meta-attributes in the CIB XML configuration
*
* \param[in,out] xml Alert or recipient XML
* \param[in,out] entry Where to store unpacked values
* \param[in,out] max_timeout Max timeout of all alerts and recipients thus far
*
* \return Standard Pacemaker return code
*/
static int
unpack_alert_options(xmlNode *xml, pcmk__alert_t *entry, guint *max_timeout)
{
GHashTable *config_hash = pcmk__strkey_table(free, free);
crm_time_t *now = crm_time_new(NULL);
const char *value = NULL;
int rc = pcmk_rc_ok;
pcmk_rule_input_t rule_input = {
.now = now,
};
pcmk_unpack_nvpair_blocks(xml, PCMK_XE_META_ATTRIBUTES, NULL, &rule_input,
config_hash, NULL);
crm_time_free(now);
value = g_hash_table_lookup(config_hash, PCMK_META_ENABLED);
if ((value != NULL) && !crm_is_true(value)) {
// No need to continue unpacking
rc = pcmk_rc_disabled;
goto done;
}
value = g_hash_table_lookup(config_hash, PCMK_META_TIMEOUT);
if (value != NULL) {
long long timeout_ms = crm_get_msec(value);
entry->timeout = (int) QB_MIN(timeout_ms, INT_MAX);
if (entry->timeout <= 0) {
if (entry->timeout == 0) {
crm_trace("Alert %s uses default timeout (%s)",
entry->id, READABLE_DEFAULT);
} else {
pcmk__config_warn("Using default timeout (%s) for alert %s "
"because '%s' is not a valid timeout",
entry->id, value, READABLE_DEFAULT);
}
entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
} else {
crm_trace("Alert %s uses timeout of %s",
entry->id, pcmk__readable_interval(entry->timeout));
}
if (entry->timeout > *max_timeout) {
*max_timeout = entry->timeout;
}
}
value = g_hash_table_lookup(config_hash, PCMK_META_TIMESTAMP_FORMAT);
if (value != NULL) {
/* hard to do any checks here as merely anything can
* can be a valid time-format-string
*/
entry->tstamp_format = strdup(value);
crm_trace("Alert %s uses timestamp format '%s'",
entry->id, entry->tstamp_format);
}
done:
g_hash_table_destroy(config_hash);
return rc;
}
/*!
* \internal
* \brief Unpack agent parameters for an alert or alert recipient into an
* environment variable list based on its CIB XML configuration
*
* \param[in] xml Alert or recipient XML
* \param[in,out] entry Alert entry to create environment variables for
*/
static void
unpack_alert_parameters(const xmlNode *xml, pcmk__alert_t *entry)
{
xmlNode *child;
if ((xml == NULL) || (entry == NULL)) {
return;
}
child = pcmk__xe_first_child(xml, PCMK_XE_INSTANCE_ATTRIBUTES, NULL,
NULL);
if (child == NULL) {
return;
}
if (entry->envvars == NULL) {
entry->envvars = pcmk__strkey_table(free, free);
}
for (child = pcmk__xe_first_child(child, PCMK_XE_NVPAIR, NULL, NULL);
child != NULL; child = pcmk__xe_next(child, PCMK_XE_NVPAIR)) {
const char *name = crm_element_value(child, PCMK_XA_NAME);
const char *value = crm_element_value(child, PCMK_XA_VALUE);
if (value == NULL) {
value = "";
}
pcmk__insert_dup(entry->envvars, name, value);
crm_trace("Alert %s: added environment variable %s='%s'",
entry->id, name, value);
}
}
+/*!
+ * \internal
+ * \brief Create filters for an alert or alert recipient based on its
+ * configuration in CIB XML
+ *
+ * \param[in] xml Alert or recipient XML
+ * \param[in,out] entry Alert entry to create filters for
+ */
static void
-unpack_alert_filter(xmlNode *basenode, pcmk__alert_t *entry)
+unpack_alert_filter(xmlNode *xml, pcmk__alert_t *entry)
{
- xmlNode *select = pcmk__xe_first_child(basenode, PCMK_XE_SELECT, NULL,
- NULL);
+ xmlNode *select = pcmk__xe_first_child(xml, PCMK_XE_SELECT, NULL, NULL);
xmlNode *event_type = NULL;
uint32_t flags = pcmk__alert_none;
for (event_type = pcmk__xe_first_child(select, NULL, NULL, NULL);
event_type != NULL; event_type = pcmk__xe_next(event_type, NULL)) {
if (pcmk__xe_is(event_type, PCMK_XE_SELECT_FENCING)) {
flags |= pcmk__alert_fencing;
} else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_NODES)) {
flags |= pcmk__alert_node;
} else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_RESOURCES)) {
flags |= pcmk__alert_resource;
} else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_ATTRIBUTES)) {
xmlNode *attr;
const char *attr_name;
int nattrs = 0;
flags |= pcmk__alert_attribute;
for (attr = pcmk__xe_first_child(event_type, PCMK_XE_ATTRIBUTE,
NULL, NULL);
attr != NULL; attr = pcmk__xe_next(attr, PCMK_XE_ATTRIBUTE)) {
attr_name = crm_element_value(attr, PCMK_XA_NAME);
if (attr_name) {
if (nattrs == 0) {
g_strfreev(entry->select_attribute_name);
entry->select_attribute_name = NULL;
}
++nattrs;
entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
(nattrs + 1) * sizeof(char*));
entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
entry->select_attribute_name[nattrs] = NULL;
}
}
}
}
if (flags != pcmk__alert_none) {
entry->flags = flags;
crm_debug("Alert %s receives events: attributes:%s%s%s%s",
entry->id,
(pcmk_is_set(flags, pcmk__alert_attribute)?
(entry->select_attribute_name? "some" : "all") : "none"),
(pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
(pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
(pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
}
}
/*!
* \internal
* \brief Unpack an alert or an alert recipient
*
* \param[in,out] alert Alert or recipient XML
* \param[in,out] entry Where to store unpacked values
* \param[in,out] max_timeout Max timeout of all alerts and recipients thus far
*
* \return Standard Pacemaker return code
*/
static int
unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
{
int rc = pcmk_rc_ok;
unpack_alert_parameters(alert, entry);
rc = unpack_alert_options(alert, entry, max_timeout);
if (rc == pcmk_rc_ok) {
unpack_alert_filter(alert, entry);
}
return rc;
}
/*!
* \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 scheduler itself,
* but is supplied for use by daemons that need to send alerts.
*/
GList *
pe_unpack_alerts(const xmlNode *alerts)
{
xmlNode *alert;
pcmk__alert_t *entry;
guint max_timeout = 0;
GList *alert_list = NULL;
if (alerts == NULL) {
return alert_list;
}
for (alert = pcmk__xe_first_child(alerts, PCMK_XE_ALERT, NULL, NULL);
alert != NULL; alert = pcmk__xe_next(alert, PCMK_XE_ALERT)) {
xmlNode *recipient;
int recipients = 0;
const char *alert_id = pcmk__xe_id(alert);
const char *alert_path = crm_element_value(alert, PCMK_XA_PATH);
/* The schema should enforce this, but to be safe ... */
if (alert_id == NULL) {
pcmk__config_warn("Ignoring invalid alert without " PCMK_XA_ID);
crm_log_xml_info(alert, "missing-id");
continue;
}
if (alert_path == NULL) {
pcmk__config_warn("Ignoring alert %s: No " PCMK_XA_PATH, alert_id);
continue;
}
entry = pcmk__alert_new(alert_id, alert_path);
if (unpack_alert(alert, entry, &max_timeout) != pcmk_rc_ok) {
// Don't allow recipients to override if entire alert is disabled
crm_debug("Alert %s is disabled", entry->id);
pcmk__free_alert(entry);
continue;
}
if (entry->tstamp_format == NULL) {
entry->tstamp_format = strdup(PCMK__ALERT_DEFAULT_TSTAMP_FORMAT);
}
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 = pcmk__xe_first_child(alert, PCMK_XE_RECIPIENT, NULL,
NULL);
recipient != NULL;
recipient = pcmk__xe_next(recipient, PCMK_XE_RECIPIENT)) {
pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
recipients++;
recipient_entry->recipient = crm_element_value_copy(recipient,
PCMK_XA_VALUE);
if (unpack_alert(recipient, recipient_entry,
&max_timeout) != pcmk_rc_ok) {
crm_debug("Alert %s: recipient %s is disabled",
entry->id, recipient_entry->id);
pcmk__free_alert(recipient_entry);
continue;
}
alert_list = g_list_prepend(alert_list, recipient_entry);
crm_debug("Alert %s has recipient %s with value %s and %d envvars",
entry->id, pcmk__xe_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, entry);
} else {
pcmk__free_alert(entry);
}
}
return alert_list;
}
/*!
* \internal
* \brief Free an alert list generated by pe_unpack_alerts()
*
* \param[in,out] alert_list Alert list to free
*/
void
pe_free_alert_list(GList *alert_list)
{
if (alert_list) {
g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 10, 3:33 AM (5 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009945
Default Alt Text
(15 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment