pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
rules_alerts.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-2023 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11#include <crm/crm.h>
12#include <crm/msg_xml.h>
13#include <crm/pengine/rules.h>
17
28static int
29get_meta_attrs_from_cib(xmlNode *basenode, pcmk__alert_t *entry,
30 guint *max_timeout)
31{
32 GHashTable *config_hash = pcmk__strkey_table(free, free);
33 crm_time_t *now = crm_time_new(NULL);
34 const char *value = NULL;
35 int rc = pcmk_rc_ok;
36
37 pe_unpack_nvpairs(basenode, basenode, XML_TAG_META_SETS, NULL, config_hash,
38 NULL, FALSE, now, NULL);
39 crm_time_free(now);
40
41 value = g_hash_table_lookup(config_hash, PCMK_META_ENABLED);
42 if ((value != NULL) && !crm_is_true(value)) {
43 // No need to continue unpacking
45 goto done;
46 }
47
48 value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TIMEOUT);
49 if (value) {
50 entry->timeout = crm_get_msec(value);
51 if (entry->timeout <= 0) {
52 if (entry->timeout == 0) {
53 crm_trace("Alert %s uses default timeout of %dmsec",
55 } else {
56 crm_warn("Alert %s has invalid timeout value '%s', using default %dmsec",
57 entry->id, (char*)value, PCMK__ALERT_DEFAULT_TIMEOUT_MS);
58 }
60 } else {
61 crm_trace("Alert %s uses timeout of %dmsec",
62 entry->id, entry->timeout);
63 }
64 if (entry->timeout > *max_timeout) {
65 *max_timeout = entry->timeout;
66 }
67 }
68 value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TSTAMP_FORMAT);
69 if (value) {
70 /* hard to do any checks here as merely anything can
71 * can be a valid time-format-string
72 */
73 entry->tstamp_format = strdup(value);
74 crm_trace("Alert %s uses timestamp format '%s'",
75 entry->id, entry->tstamp_format);
76 }
77
78done:
79 g_hash_table_destroy(config_hash);
80 return rc;
81}
82
83static void
84get_envvars_from_cib(xmlNode *basenode, pcmk__alert_t *entry)
85{
86 xmlNode *child;
87
88 if ((basenode == NULL) || (entry == NULL)) {
89 return;
90 }
91
92 child = first_named_child(basenode, XML_TAG_ATTR_SETS);
93 if (child == NULL) {
94 return;
95 }
96
97 if (entry->envvars == NULL) {
98 entry->envvars = pcmk__strkey_table(free, free);
99 }
100
101 for (child = first_named_child(child, XML_CIB_TAG_NVPAIR); child != NULL;
102 child = crm_next_same_xml(child)) {
103
104 const char *name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
105 const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE);
106
107 if (value == NULL) {
108 value = "";
109 }
110 g_hash_table_insert(entry->envvars, strdup(name), strdup(value));
111 crm_trace("Alert %s: added environment variable %s='%s'",
112 entry->id, name, value);
113 }
114}
115
116static void
117unpack_alert_filter(xmlNode *basenode, pcmk__alert_t *entry)
118{
119 xmlNode *select = first_named_child(basenode, XML_CIB_TAG_ALERT_SELECT);
120 xmlNode *event_type = NULL;
121 uint32_t flags = pcmk__alert_none;
122
123 for (event_type = pcmk__xe_first_child(select); event_type != NULL;
124 event_type = pcmk__xe_next(event_type)) {
125
126 if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_FENCING)) {
128
129 } else if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_NODES)) {
131
132 } else if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_RESOURCES)) {
134
135 } else if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_ATTRIBUTES)) {
136 xmlNode *attr;
137 const char *attr_name;
138 int nattrs = 0;
139
141 for (attr = first_named_child(event_type, XML_CIB_TAG_ALERT_ATTR);
142 attr != NULL;
143 attr = crm_next_same_xml(attr)) {
144
145 attr_name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
146 if (attr_name) {
147 if (nattrs == 0) {
148 g_strfreev(entry->select_attribute_name);
149 entry->select_attribute_name = NULL;
150 }
151 ++nattrs;
152 entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
153 (nattrs + 1) * sizeof(char*));
154 entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
155 entry->select_attribute_name[nattrs] = NULL;
156 }
157 }
158 }
159 }
160
161 if (flags != pcmk__alert_none) {
162 entry->flags = flags;
163 crm_debug("Alert %s receives events: attributes:%s%s%s%s",
164 entry->id,
166 (entry->select_attribute_name? "some" : "all") : "none"),
167 (pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
168 (pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
169 (pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
170 }
171}
172
183static int
184unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
185{
186 int rc = pcmk_rc_ok;
187
188 get_envvars_from_cib(alert, entry);
189 rc = get_meta_attrs_from_cib(alert, entry, max_timeout);
190 if (rc == pcmk_rc_ok) {
191 unpack_alert_filter(alert, entry);
192 }
193 return rc;
194}
195
207GList *
208pe_unpack_alerts(const xmlNode *alerts)
209{
210 xmlNode *alert;
211 pcmk__alert_t *entry;
212 guint max_timeout = 0;
213 GList *alert_list = NULL;
214
215 if (alerts == NULL) {
216 return alert_list;
217 }
218
219 for (alert = first_named_child(alerts, XML_CIB_TAG_ALERT);
220 alert != NULL; alert = crm_next_same_xml(alert)) {
221
222 xmlNode *recipient;
223 int recipients = 0;
224 const char *alert_id = ID(alert);
225 const char *alert_path = crm_element_value(alert, XML_ALERT_ATTR_PATH);
226
227 /* The schema should enforce this, but to be safe ... */
228 if ((alert_id == NULL) || (alert_path == NULL)) {
229 crm_warn("Ignoring invalid alert without id and path");
230 continue;
231 }
232
233 entry = pcmk__alert_new(alert_id, alert_path);
234
235 if (unpack_alert(alert, entry, &max_timeout) != pcmk_rc_ok) {
236 // Don't allow recipients to override if entire alert is disabled
237 crm_debug("Alert %s is disabled", entry->id);
238 pcmk__free_alert(entry);
239 continue;
240 }
241
242 if (entry->tstamp_format == NULL) {
244 }
245
246 crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars",
247 entry->id, entry->path, entry->timeout, entry->tstamp_format,
248 (entry->envvars? g_hash_table_size(entry->envvars) : 0));
249
250 for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT);
251 recipient != NULL; recipient = crm_next_same_xml(recipient)) {
252
253 pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
254
255 recipients++;
256 recipient_entry->recipient = strdup(crm_element_value(recipient,
258
259 if (unpack_alert(recipient, recipient_entry,
260 &max_timeout) != pcmk_rc_ok) {
261 crm_debug("Alert %s: recipient %s is disabled",
262 entry->id, recipient_entry->id);
263 pcmk__free_alert(recipient_entry);
264 continue;
265 }
266 alert_list = g_list_prepend(alert_list, recipient_entry);
267 crm_debug("Alert %s has recipient %s with value %s and %d envvars",
268 entry->id, ID(recipient), recipient_entry->recipient,
269 (recipient_entry->envvars?
270 g_hash_table_size(recipient_entry->envvars) : 0));
271 }
272
273 if (recipients == 0) {
274 alert_list = g_list_prepend(alert_list, entry);
275 } else {
276 pcmk__free_alert(entry);
277 }
278 }
279 return alert_list;
280}
281
288void
289pe_free_alert_list(GList *alert_list)
290{
291 if (alert_list) {
292 g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
293 }
294}
#define PCMK__ALERT_DEFAULT_TSTAMP_FORMAT
void pcmk__free_alert(pcmk__alert_t *entry)
Definition alerts.c:108
pcmk__alert_t * pcmk__alert_new(const char *id, const char *path)
Create a new alert entry structure.
Definition alerts.c:95
pcmk__alert_t * pcmk__dup_alert(const pcmk__alert_t *entry)
Definition alerts.c:133
#define PCMK__ALERT_DEFAULT_TIMEOUT_MS
@ pcmk__alert_resource
@ pcmk__alert_none
@ pcmk__alert_attribute
@ pcmk__alert_fencing
@ pcmk__alert_node
const char * name
Definition cib.c:26
uint64_t flags
Definition remote.c:3
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition strings.c:364
gboolean crm_is_true(const char *s)
Definition strings.c:416
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:99
A dumping ground.
void crm_time_free(crm_time_t *dt)
Definition iso8601.c:150
crm_time_t * crm_time_new(const char *string)
Definition iso8601.c:109
struct crm_time_s crm_time_t
Definition iso8601.h:32
#define crm_warn(fmt, args...)
Definition logging.h:380
#define crm_debug(fmt, args...)
Definition logging.h:384
#define crm_trace(fmt, args...)
Definition logging.h:385
#define XML_CIB_TAG_ALERT_ATTRIBUTES
Definition msg_xml.h:216
#define ID(x)
Definition msg_xml.h:474
#define XML_CIB_TAG_ALERT
Definition msg_xml.h:213
#define XML_CIB_TAG_ALERT_SELECT
Definition msg_xml.h:215
#define XML_CIB_TAG_ALERT_RECIPIENT
Definition msg_xml.h:214
#define XML_CIB_TAG_ALERT_RESOURCES
Definition msg_xml.h:219
#define XML_NVPAIR_ATTR_VALUE
Definition msg_xml.h:394
#define XML_ALERT_ATTR_PATH
Definition msg_xml.h:408
#define XML_TAG_ATTR_SETS
Definition msg_xml.h:227
#define PCMK_META_ENABLED
Definition msg_xml.h:67
#define XML_CIB_TAG_ALERT_FENCING
Definition msg_xml.h:217
#define XML_TAG_META_SETS
Definition msg_xml.h:228
#define XML_NVPAIR_ATTR_NAME
Definition msg_xml.h:393
#define XML_ALERT_ATTR_TSTAMP_FORMAT
Definition msg_xml.h:410
#define XML_CIB_TAG_NVPAIR
Definition msg_xml.h:224
#define XML_ALERT_ATTR_TIMEOUT
Definition msg_xml.h:409
#define XML_CIB_TAG_ALERT_ATTR
Definition msg_xml.h:220
#define XML_CIB_TAG_ALERT_NODES
Definition msg_xml.h:218
#define XML_ALERT_ATTR_REC_VALUE
Definition msg_xml.h:411
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:447
@ pcmk_rc_disabled
Definition results.h:116
@ pcmk_rc_ok
Definition results.h:154
void pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition rules.c:535
GList * pe_unpack_alerts(const xmlNode *alerts)
void pe_free_alert_list(GList *alert_list)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:608
char ** select_attribute_name
GHashTable * envvars
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2484
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition xml.c:2510