This source file includes following definitions.
- pcmk__alert_new
- pcmk__free_alert
- pcmk__dup_alert
- pcmk__add_alert_key
- pcmk__add_alert_key_int
- unpack_alert_options
- unpack_alert_parameters
- unpack_alert_filter
- unpack_alert
- pcmk__unpack_alerts
- pcmk__free_alerts
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/lrmd.h>
13 #include <crm/common/xml.h>
14 #include <crm/common/alerts_internal.h>
15 #include <crm/common/cib_internal.h>
16 #include <crm/common/xml_internal.h>
17
18 const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX] = {
19 [PCMK__alert_key_recipient] = "CRM_alert_recipient",
20 [PCMK__alert_key_node] = "CRM_alert_node",
21 [PCMK__alert_key_nodeid] = "CRM_alert_nodeid",
22 [PCMK__alert_key_rsc] = "CRM_alert_rsc",
23 [PCMK__alert_key_task] = "CRM_alert_task",
24 [PCMK__alert_key_interval] = "CRM_alert_interval",
25 [PCMK__alert_key_desc] = "CRM_alert_desc",
26 [PCMK__alert_key_status] = "CRM_alert_status",
27 [PCMK__alert_key_target_rc] = "CRM_alert_target_rc",
28 [PCMK__alert_key_rc] = "CRM_alert_rc",
29 [PCMK__alert_key_kind] = "CRM_alert_kind",
30 [PCMK__alert_key_version] = "CRM_alert_version",
31 [PCMK__alert_key_node_sequence] = PCMK__ALERT_NODE_SEQUENCE,
32 [PCMK__alert_key_timestamp] = "CRM_alert_timestamp",
33 [PCMK__alert_key_attribute_name] = "CRM_alert_attribute_name",
34 [PCMK__alert_key_attribute_value] = "CRM_alert_attribute_value",
35 [PCMK__alert_key_timestamp_epoch] = "CRM_alert_timestamp_epoch",
36 [PCMK__alert_key_timestamp_usec] = "CRM_alert_timestamp_usec",
37 [PCMK__alert_key_exec_time] = "CRM_alert_exec_time",
38 };
39
40
41
42
43
44
45
46
47
48
49
50
51 pcmk__alert_t *
52 pcmk__alert_new(const char *id, const char *path)
53 {
54 pcmk__alert_t *entry = pcmk__assert_alloc(1, sizeof(pcmk__alert_t));
55
56 pcmk__assert((id != NULL) && (path != NULL));
57 entry->id = pcmk__str_copy(id);
58 entry->path = pcmk__str_copy(path);
59 entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
60 entry->flags = pcmk__alert_default;
61 return entry;
62 }
63
64 void
65 pcmk__free_alert(pcmk__alert_t *entry)
66 {
67 if (entry) {
68 free(entry->id);
69 free(entry->path);
70 free(entry->tstamp_format);
71 free(entry->recipient);
72
73 g_strfreev(entry->select_attribute_name);
74 if (entry->envvars) {
75 g_hash_table_destroy(entry->envvars);
76 }
77 free(entry);
78 }
79 }
80
81
82
83
84
85
86
87
88
89 pcmk__alert_t *
90 pcmk__dup_alert(const pcmk__alert_t *entry)
91 {
92 pcmk__alert_t *new_entry = pcmk__alert_new(entry->id, entry->path);
93
94 new_entry->timeout = entry->timeout;
95 new_entry->flags = entry->flags;
96 new_entry->envvars = pcmk__str_table_dup(entry->envvars);
97 new_entry->tstamp_format = pcmk__str_copy(entry->tstamp_format);
98 new_entry->recipient = pcmk__str_copy(entry->recipient);
99 if (entry->select_attribute_name) {
100 new_entry->select_attribute_name = g_strdupv(entry->select_attribute_name);
101 }
102 return new_entry;
103 }
104
105 void
106 pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name,
107 const char *value)
108 {
109 pcmk__assert((table != NULL) && (name >= 0)
110 && (name < PCMK__ALERT_INTERNAL_KEY_MAX));
111 if (value == NULL) {
112 crm_trace("Removing alert key %s", pcmk__alert_keys[name]);
113 g_hash_table_remove(table, pcmk__alert_keys[name]);
114 } else {
115 crm_trace("Inserting alert key %s = '%s'",
116 pcmk__alert_keys[name], value);
117 pcmk__insert_dup(table, pcmk__alert_keys[name], value);
118 }
119 }
120
121 void
122 pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name,
123 int value)
124 {
125 pcmk__assert((table != NULL) && (name >= 0)
126 && (name < PCMK__ALERT_INTERNAL_KEY_MAX));
127 crm_trace("Inserting alert key %s = %d", pcmk__alert_keys[name], value);
128 g_hash_table_insert(table, pcmk__str_copy(pcmk__alert_keys[name]),
129 pcmk__itoa(value));
130 }
131
132 #define READABLE_DEFAULT pcmk__readable_interval(PCMK__ALERT_DEFAULT_TIMEOUT_MS)
133
134
135
136
137
138
139
140
141
142
143
144
145 static int
146 unpack_alert_options(xmlNode *xml, pcmk__alert_t *entry, guint *max_timeout)
147 {
148 GHashTable *config_hash = pcmk__strkey_table(free, free);
149 crm_time_t *now = crm_time_new(NULL);
150 const char *value = NULL;
151 int rc = pcmk_rc_ok;
152
153 pcmk_rule_input_t rule_input = {
154 .now = now,
155 };
156
157 pcmk_unpack_nvpair_blocks(xml, PCMK_XE_META_ATTRIBUTES, NULL, &rule_input,
158 config_hash, NULL);
159 crm_time_free(now);
160
161 value = g_hash_table_lookup(config_hash, PCMK_META_ENABLED);
162 if ((value != NULL) && !crm_is_true(value)) {
163
164 rc = pcmk_rc_disabled;
165 goto done;
166 }
167
168 value = g_hash_table_lookup(config_hash, PCMK_META_TIMEOUT);
169 if (value != NULL) {
170 long long timeout_ms = crm_get_msec(value);
171
172 entry->timeout = (int) QB_MIN(timeout_ms, INT_MAX);
173 if (entry->timeout <= 0) {
174 if (entry->timeout == 0) {
175 crm_trace("Alert %s uses default timeout (%s)",
176 entry->id, READABLE_DEFAULT);
177 } else {
178 pcmk__config_warn("Using default timeout (%s) for alert %s "
179 "because '%s' is not a valid timeout",
180 entry->id, value, READABLE_DEFAULT);
181 }
182 entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
183 } else {
184 crm_trace("Alert %s uses timeout of %s",
185 entry->id, pcmk__readable_interval(entry->timeout));
186 }
187 if (entry->timeout > *max_timeout) {
188 *max_timeout = entry->timeout;
189 }
190 }
191 value = g_hash_table_lookup(config_hash, PCMK_META_TIMESTAMP_FORMAT);
192 if (value != NULL) {
193
194
195
196 entry->tstamp_format = strdup(value);
197 crm_trace("Alert %s uses timestamp format '%s'",
198 entry->id, entry->tstamp_format);
199 }
200
201 done:
202 g_hash_table_destroy(config_hash);
203 return rc;
204 }
205
206
207
208
209
210
211
212
213
214 static void
215 unpack_alert_parameters(const xmlNode *xml, pcmk__alert_t *entry)
216 {
217 xmlNode *child;
218
219 if ((xml == NULL) || (entry == NULL)) {
220 return;
221 }
222
223 child = pcmk__xe_first_child(xml, PCMK_XE_INSTANCE_ATTRIBUTES, NULL,
224 NULL);
225 if (child == NULL) {
226 return;
227 }
228
229 if (entry->envvars == NULL) {
230 entry->envvars = pcmk__strkey_table(free, free);
231 }
232
233 for (child = pcmk__xe_first_child(child, PCMK_XE_NVPAIR, NULL, NULL);
234 child != NULL; child = pcmk__xe_next(child, PCMK_XE_NVPAIR)) {
235
236 const char *name = crm_element_value(child, PCMK_XA_NAME);
237 const char *value = crm_element_value(child, PCMK_XA_VALUE);
238
239 if (value == NULL) {
240 value = "";
241 }
242 pcmk__insert_dup(entry->envvars, name, value);
243 crm_trace("Alert %s: added environment variable %s='%s'",
244 entry->id, name, value);
245 }
246 }
247
248
249
250
251
252
253
254
255
256 static void
257 unpack_alert_filter(xmlNode *xml, pcmk__alert_t *entry)
258 {
259 xmlNode *select = pcmk__xe_first_child(xml, PCMK_XE_SELECT, NULL, NULL);
260 xmlNode *event_type = NULL;
261 uint32_t flags = pcmk__alert_none;
262
263 for (event_type = pcmk__xe_first_child(select, NULL, NULL, NULL);
264 event_type != NULL; event_type = pcmk__xe_next(event_type, NULL)) {
265
266 if (pcmk__xe_is(event_type, PCMK_XE_SELECT_FENCING)) {
267 flags |= pcmk__alert_fencing;
268
269 } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_NODES)) {
270 flags |= pcmk__alert_node;
271
272 } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_RESOURCES)) {
273 flags |= pcmk__alert_resource;
274
275 } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_ATTRIBUTES)) {
276 xmlNode *attr;
277 const char *attr_name;
278 int nattrs = 0;
279
280 flags |= pcmk__alert_attribute;
281 for (attr = pcmk__xe_first_child(event_type, PCMK_XE_ATTRIBUTE,
282 NULL, NULL);
283 attr != NULL; attr = pcmk__xe_next(attr, PCMK_XE_ATTRIBUTE)) {
284
285 attr_name = crm_element_value(attr, PCMK_XA_NAME);
286 if (attr_name) {
287 if (nattrs == 0) {
288 g_strfreev(entry->select_attribute_name);
289 entry->select_attribute_name = NULL;
290 }
291 ++nattrs;
292 entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
293 (nattrs + 1) * sizeof(char*));
294 entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
295 entry->select_attribute_name[nattrs] = NULL;
296 }
297 }
298 }
299 }
300
301 if (flags != pcmk__alert_none) {
302 entry->flags = flags;
303 crm_debug("Alert %s receives events: attributes:%s%s%s%s",
304 entry->id,
305 (pcmk_is_set(flags, pcmk__alert_attribute)?
306 (entry->select_attribute_name? "some" : "all") : "none"),
307 (pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
308 (pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
309 (pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
310 }
311 }
312
313
314
315
316
317
318
319
320
321
322
323 static int
324 unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
325 {
326 int rc = pcmk_rc_ok;
327
328 unpack_alert_parameters(alert, entry);
329 rc = unpack_alert_options(alert, entry, max_timeout);
330 if (rc == pcmk_rc_ok) {
331 unpack_alert_filter(alert, entry);
332 }
333 return rc;
334 }
335
336
337
338
339
340
341
342
343
344 GList *
345 pcmk__unpack_alerts(const xmlNode *alerts)
346 {
347 xmlNode *alert;
348 pcmk__alert_t *entry;
349 guint max_timeout = 0U;
350 GList *alert_list = NULL;
351
352 for (alert = pcmk__xe_first_child(alerts, PCMK_XE_ALERT, NULL, NULL);
353 alert != NULL; alert = pcmk__xe_next(alert, PCMK_XE_ALERT)) {
354
355 xmlNode *recipient = NULL;
356 int recipients = 0;
357 const char *alert_id = pcmk__xe_id(alert);
358 const char *alert_path = crm_element_value(alert, PCMK_XA_PATH);
359
360
361 if (alert_id == NULL) {
362 pcmk__config_err("Ignoring invalid alert without " PCMK_XA_ID);
363 continue;
364 }
365 if (alert_path == NULL) {
366 pcmk__config_err("Ignoring invalid alert %s without " PCMK_XA_PATH,
367 alert_id);
368 continue;
369 }
370
371 entry = pcmk__alert_new(alert_id, alert_path);
372
373 if (unpack_alert(alert, entry, &max_timeout) != pcmk_rc_ok) {
374
375 crm_debug("Alert %s is disabled", entry->id);
376 pcmk__free_alert(entry);
377 continue;
378 }
379
380 if (entry->tstamp_format == NULL) {
381 entry->tstamp_format =
382 pcmk__str_copy(PCMK__ALERT_DEFAULT_TSTAMP_FORMAT);
383 }
384
385 crm_debug("Alert %s: path=%s timeout=%s tstamp-format='%s'",
386 entry->id, entry->path,
387 pcmk__readable_interval(entry->timeout),
388 entry->tstamp_format);
389
390 for (recipient = pcmk__xe_first_child(alert, PCMK_XE_RECIPIENT, NULL,
391 NULL);
392 recipient != NULL;
393 recipient = pcmk__xe_next(recipient, PCMK_XE_RECIPIENT)) {
394
395 pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
396
397 recipients++;
398 recipient_entry->recipient = crm_element_value_copy(recipient,
399 PCMK_XA_VALUE);
400
401 if (unpack_alert(recipient, recipient_entry,
402 &max_timeout) != pcmk_rc_ok) {
403 crm_debug("Alert %s: recipient %s is disabled",
404 entry->id, recipient_entry->id);
405 pcmk__free_alert(recipient_entry);
406 continue;
407 }
408 alert_list = g_list_prepend(alert_list, recipient_entry);
409 crm_debug("Alert %s has recipient %s with value %s and %d envvars",
410 entry->id, pcmk__xe_id(recipient),
411 recipient_entry->recipient,
412 (recipient_entry->envvars?
413 g_hash_table_size(recipient_entry->envvars) : 0));
414 }
415
416 if (recipients == 0) {
417 alert_list = g_list_prepend(alert_list, entry);
418 } else {
419 pcmk__free_alert(entry);
420 }
421 }
422 return alert_list;
423 }
424
425
426
427
428
429
430
431 void
432 pcmk__free_alerts(GList *alert_list)
433 {
434 if (alert_list != NULL) {
435 g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
436 }
437 }