pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
lrmd_alerts.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-2021 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
12#include <glib.h>
13#include <unistd.h>
14
15#include <crm/crm.h>
16#include <crm/msg_xml.h>
17#include <crm/services.h>
18#include <crm/common/mainloop.h>
20#include <crm/lrmd_internal.h>
21
22#include <crm/pengine/status.h>
23#include <crm/cib.h>
24#include <crm/lrmd.h>
25
26static lrmd_key_value_t *
27alert_key2param(lrmd_key_value_t *head, enum pcmk__alert_keys_e name,
28 const char *value)
29{
30 const char **key;
31
32 if (value == NULL) {
33 value = "";
34 }
35 for (key = pcmk__alert_keys[name]; *key; key++) {
36 crm_trace("Setting alert key %s = '%s'", *key, value);
37 head = lrmd_key_value_add(head, *key, value);
38 }
39 return head;
40}
41
42static lrmd_key_value_t *
43alert_key2param_int(lrmd_key_value_t *head, enum pcmk__alert_keys_e name,
44 int value)
45{
46 char *value_s = pcmk__itoa(value);
47
48 head = alert_key2param(head, name, value_s);
49 free(value_s);
50 return head;
51}
52
53static lrmd_key_value_t *
54alert_key2param_ms(lrmd_key_value_t *head, enum pcmk__alert_keys_e name,
55 guint value)
56{
57 char *value_s = crm_strdup_printf("%u", value);
58
59 head = alert_key2param(head, name, value_s);
60 free(value_s);
61 return head;
62}
63
64static void
65set_ev_kv(gpointer key, gpointer value, gpointer user_data)
66{
67 lrmd_key_value_t **head = (lrmd_key_value_t **) user_data;
68
69 if (value) {
70 crm_trace("Setting environment variable %s='%s'",
71 (char*)key, (char*)value);
72 *head = lrmd_key_value_add(*head, key, value);
73 }
74}
75
76static lrmd_key_value_t *
77alert_envvar2params(lrmd_key_value_t *head, pcmk__alert_t *entry)
78{
79 if (entry->envvars) {
80 g_hash_table_foreach(entry->envvars, set_ev_kv, &head);
81 }
82 return head;
83}
84
85/*
86 * We could use g_strv_contains() instead of this function,
87 * but that has only been available since glib 2.43.2.
88 */
89static gboolean
90is_target_alert(char **list, const char *value)
91{
92 int target_list_num = 0;
93 gboolean rc = FALSE;
94
95 CRM_CHECK(value != NULL, return FALSE);
96
97 if (list == NULL) {
98 return TRUE;
99 }
100
101 target_list_num = g_strv_length(list);
102
103 for (int cnt = 0; cnt < target_list_num; cnt++) {
104 if (strcmp(list[cnt], value) == 0) {
105 rc = TRUE;
106 break;
107 }
108 }
109 return rc;
110}
111
126static int
127exec_alert_list(lrmd_t *lrmd, GList *alert_list, enum pcmk__alert_flags kind,
128 const char *attr_name, lrmd_key_value_t *params)
129{
130 bool any_success = FALSE, any_failure = FALSE;
131 const char *kind_s = pcmk__alert_flag2text(kind);
132 pcmk__time_hr_t *now = NULL;
133 char timestamp_epoch[20];
134 char timestamp_usec[7];
135 time_t epoch = 0;
136
137 params = alert_key2param(params, PCMK__alert_key_kind, kind_s);
138 params = alert_key2param(params, PCMK__alert_key_version,
140
141 for (GList *iter = g_list_first(alert_list); iter; iter = g_list_next(iter)) {
142 pcmk__alert_t *entry = (pcmk__alert_t *)(iter->data);
143 lrmd_key_value_t *copy_params = NULL;
144 lrmd_key_value_t *head = NULL;
145 int rc;
146
147 if (!pcmk_is_set(entry->flags, kind)) {
148 crm_trace("Filtering unwanted %s alert to %s via %s",
149 kind_s, entry->recipient, entry->id);
150 continue;
151 }
152
153 if ((kind == pcmk__alert_attribute)
154 && !is_target_alert(entry->select_attribute_name, attr_name)) {
155
156 crm_trace("Filtering unwanted attribute '%s' alert to %s via %s",
157 attr_name, entry->recipient, entry->id);
158 continue;
159 }
160
161 if (now == NULL) {
162 now = pcmk__time_hr_now(&epoch);
163 }
164 crm_info("Sending %s alert via %s to %s",
165 kind_s, entry->id, entry->recipient);
166
167 /* Make a copy of the parameters, because each alert will be unique */
168 for (head = params; head != NULL; head = head->next) {
169 copy_params = lrmd_key_value_add(copy_params, head->key, head->value);
170 }
171
172 copy_params = alert_key2param(copy_params, PCMK__alert_key_recipient,
173 entry->recipient);
174
175 if (now) {
176 char *timestamp = pcmk__time_format_hr(entry->tstamp_format, now);
177
178 if (timestamp) {
179 copy_params = alert_key2param(copy_params,
181 timestamp);
182 free(timestamp);
183 }
184
185 snprintf(timestamp_epoch, sizeof(timestamp_epoch), "%lld",
186 (long long) epoch);
187 copy_params = alert_key2param(copy_params,
189 timestamp_epoch);
190 snprintf(timestamp_usec, sizeof(timestamp_usec), "%06d", now->useconds);
191 copy_params = alert_key2param(copy_params,
193 timestamp_usec);
194 }
195
196 copy_params = alert_envvar2params(copy_params, entry);
197
198 rc = lrmd->cmds->exec_alert(lrmd, entry->id, entry->path,
199 entry->timeout, copy_params);
200 if (rc < 0) {
201 crm_err("Could not execute alert %s: %s " CRM_XS " rc=%d",
202 entry->id, pcmk_strerror(rc), rc);
203 any_failure = TRUE;
204 } else {
205 any_success = TRUE;
206 }
207 }
208
209 if (now) {
210 free(now);
211 }
212
213 if (any_failure) {
214 return (any_success? -1 : -2);
215 }
216 return pcmk_ok;
217}
218
234int
235lrmd_send_attribute_alert(lrmd_t *lrmd, GList *alert_list,
236 const char *node, uint32_t nodeid,
237 const char *attr_name, const char *attr_value)
238{
239 int rc = pcmk_ok;
240 lrmd_key_value_t *params = NULL;
241
242 if (lrmd == NULL) {
243 return -2;
244 }
245
246 params = alert_key2param(params, PCMK__alert_key_node, node);
247 params = alert_key2param_int(params, PCMK__alert_key_nodeid, nodeid);
248 params = alert_key2param(params, PCMK__alert_key_attribute_name, attr_name);
249 params = alert_key2param(params, PCMK__alert_key_attribute_value,
250 attr_value);
251
252 rc = exec_alert_list(lrmd, alert_list, pcmk__alert_attribute, attr_name,
253 params);
255 return rc;
256}
257
272int
273lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list,
274 const char *node, uint32_t nodeid, const char *state)
275{
276 int rc = pcmk_ok;
277 lrmd_key_value_t *params = NULL;
278
279 if (lrmd == NULL) {
280 return -2;
281 }
282
283 params = alert_key2param(params, PCMK__alert_key_node, node);
284 params = alert_key2param(params, PCMK__alert_key_desc, state);
285 params = alert_key2param_int(params, PCMK__alert_key_nodeid, nodeid);
286
287 rc = exec_alert_list(lrmd, alert_list, pcmk__alert_node, NULL, params);
289 return rc;
290}
291
307int
308lrmd_send_fencing_alert(lrmd_t *lrmd, GList *alert_list,
309 const char *target, const char *task, const char *desc,
310 int op_rc)
311{
312 int rc = pcmk_ok;
313 lrmd_key_value_t *params = NULL;
314
315 if (lrmd == NULL) {
316 return -2;
317 }
318
319 params = alert_key2param(params, PCMK__alert_key_node, target);
320 params = alert_key2param(params, PCMK__alert_key_task, task);
321 params = alert_key2param(params, PCMK__alert_key_desc, desc);
322 params = alert_key2param_int(params, PCMK__alert_key_rc, op_rc);
323
324 rc = exec_alert_list(lrmd, alert_list, pcmk__alert_fencing, NULL, params);
326 return rc;
327}
328
342int
343lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list,
344 const char *node, lrmd_event_data_t *op)
345{
346 int rc = pcmk_ok;
347 int target_rc = pcmk_ok;
348 lrmd_key_value_t *params = NULL;
349
350 if (lrmd == NULL) {
351 return -2;
352 }
353
354 target_rc = rsc_op_expected_rc(op);
355 if ((op->interval_ms == 0) && (target_rc == op->rc)
356 && pcmk__str_eq(op->op_type, RSC_STATUS, pcmk__str_casei)) {
357
358 /* Don't send alerts for probes with the expected result. Leave it up to
359 * the agent whether to alert for 'failed' probes. (Even if we find a
360 * resource running, it was probably because someone did a clean-up of
361 * the status section.)
362 */
363 return pcmk_ok;
364 }
365
366 params = alert_key2param(params, PCMK__alert_key_node, node);
367 params = alert_key2param(params, PCMK__alert_key_rsc, op->rsc_id);
368 params = alert_key2param(params, PCMK__alert_key_task, op->op_type);
369 params = alert_key2param_ms(params, PCMK__alert_key_interval,
370 op->interval_ms);
371 params = alert_key2param_int(params, PCMK__alert_key_target_rc, target_rc);
372 params = alert_key2param_int(params, PCMK__alert_key_status, op->op_status);
373 params = alert_key2param_int(params, PCMK__alert_key_rc, op->rc);
374
375 /* Reoccurring operations do not set exec_time, so on timeout, set it
376 * to the operation timeout since that's closer to the actual value.
377 */
378 if ((op->op_status == PCMK_EXEC_TIMEOUT) && (op->exec_time == 0)) {
379 params = alert_key2param_int(params, PCMK__alert_key_exec_time,
380 op->timeout);
381 } else {
382 params = alert_key2param_int(params, PCMK__alert_key_exec_time,
383 op->exec_time);
384 }
385
386 if (op->op_status == PCMK_EXEC_DONE) {
387 params = alert_key2param(params, PCMK__alert_key_desc,
388 services_ocf_exitcode_str(op->rc));
389 } else {
390 params = alert_key2param(params, PCMK__alert_key_desc,
391 pcmk_exec_status_str(op->op_status));
392 }
393
394 rc = exec_alert_list(lrmd, alert_list, pcmk__alert_resource, NULL, params);
396 return rc;
397}
const char * pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX][3]
Definition: alerts.c:22
pcmk__alert_keys_e
@ PCMK__alert_key_node
@ PCMK__alert_key_task
@ PCMK__alert_key_timestamp_epoch
@ PCMK__alert_key_rc
@ PCMK__alert_key_status
@ PCMK__alert_key_nodeid
@ PCMK__alert_key_interval
@ PCMK__alert_key_timestamp
@ PCMK__alert_key_attribute_name
@ PCMK__alert_key_target_rc
@ PCMK__alert_key_timestamp_usec
@ PCMK__alert_key_kind
@ PCMK__alert_key_rsc
@ PCMK__alert_key_recipient
@ PCMK__alert_key_exec_time
@ PCMK__alert_key_version
@ PCMK__alert_key_desc
@ PCMK__alert_key_attribute_value
pcmk__alert_flags
@ pcmk__alert_resource
@ pcmk__alert_attribute
@ pcmk__alert_fencing
@ pcmk__alert_node
const char * name
Definition: cib.c:24
Cluster Configuration.
int rsc_op_expected_rc(lrmd_event_data_t *event)
Definition: operations.c:426
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
#define PACEMAKER_VERSION
Definition: config.h:502
A dumping ground.
#define RSC_STATUS
Definition: crm.h:213
char * pcmk__time_format_hr(const char *format, const pcmk__time_hr_t *hr_dt)
Definition: iso8601.c:1646
pcmk__time_hr_t * pcmk__time_hr_now(time_t *epoch)
Definition: iso8601.c:1604
#define crm_info(fmt, args...)
Definition: logging.h:362
#define CRM_XS
Definition: logging.h:55
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_trace(fmt, args...)
Definition: logging.h:365
Resource agent executor.
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *kvp, const char *key, const char *value)
Definition: lrmd_client.c:146
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:169
int lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list, const char *node, uint32_t nodeid, const char *state)
Definition: lrmd_alerts.c:273
int lrmd_send_attribute_alert(lrmd_t *lrmd, GList *alert_list, const char *node, uint32_t nodeid, const char *attr_name, const char *attr_value)
Definition: lrmd_alerts.c:235
int lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list, const char *node, lrmd_event_data_t *op)
Definition: lrmd_alerts.c:343
int lrmd_send_fencing_alert(lrmd_t *lrmd, GList *alert_list, const char *target, const char *task, const char *desc, int op_rc)
Definition: lrmd_alerts.c:308
Wrappers for and extensions to glib mainloop.
const char * target
Definition: pcmk_fence.c:29
const char * pcmk_strerror(int rc)
Definition: results.c:148
#define pcmk_ok
Definition: results.h:68
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition: results.h:312
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition: results.h:314
Services API.
Cluster status and scheduling.
@ pcmk__str_casei
int(* exec_alert)(lrmd_t *lrmd, const char *alert_id, const char *alert_path, int timeout, lrmd_key_value_t *params)
Execute an alert agent.
Definition: lrmd.h:570
const char * op_type
Definition: lrmd.h:223
unsigned int exec_time
Definition: lrmd.h:249
enum ocf_exitcode rc
Definition: lrmd.h:239
guint interval_ms
Definition: lrmd.h:232
const char * rsc_id
Definition: lrmd.h:221
char * key
Definition: lrmd.h:30
struct lrmd_key_value_s * next
Definition: lrmd.h:32
char * value
Definition: lrmd.h:31
Definition: lrmd.h:597
lrmd_api_operations_t * cmds
Definition: lrmd.h:598
char ** select_attribute_name
char * tstamp_format
GHashTable * envvars