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