pacemaker  2.1.5-b7adf64e51
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 
26 static lrmd_key_value_t *
27 alert_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 
42 static lrmd_key_value_t *
43 alert_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 
53 static lrmd_key_value_t *
54 alert_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 
64 static void
65 set_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 
76 static lrmd_key_value_t *
77 alert_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  */
89 static gboolean
90 is_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 
126 static int
127 exec_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 
234 int
235 lrmd_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);
254  lrmd_key_value_freeall(params);
255  return rc;
256 }
257 
272 int
273 lrmd_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);
288  lrmd_key_value_freeall(params);
289  return rc;
290 }
291 
307 int
308 lrmd_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);
325  lrmd_key_value_freeall(params);
326  return rc;
327 }
328 
342 int
343 lrmd_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);
395  lrmd_key_value_freeall(params);
396  return rc;
397 }
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:148
const char * rsc_id
Definition: lrmd.h:221
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
const char * name
Definition: cib.c:24
int rsc_op_expected_rc(lrmd_event_data_t *event)
Definition: operations.c:426
char ** select_attribute_name
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
char * tstamp_format
Resource agent executor.
enum ocf_exitcode rc
Definition: lrmd.h:239
pcmk__alert_keys_e
Action did not complete in time.
Definition: results.h:314
#define PACEMAKER_VERSION
Definition: config.h:505
Wrappers for and extensions to glib mainloop.
unsigned int exec_time
Definition: lrmd.h:249
const char * pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX][3]
Definition: alerts.c:22
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
char * key
Definition: lrmd.h:30
#define crm_trace(fmt, args...)
Definition: logging.h:365
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
Action completed, result is known.
Definition: results.h:312
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
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *kvp, const char *key, const char *value)
Definition: lrmd_client.c:146
pcmk__time_hr_t * pcmk__time_hr_now(time_t *epoch)
Definition: iso8601.c:1604
struct lrmd_key_value_s * next
Definition: lrmd.h:32
GHashTable * envvars
int lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list, const char *node, lrmd_event_data_t *op)
Definition: lrmd_alerts.c:343
const char * op_type
Definition: lrmd.h:223
const char * target
Definition: pcmk_fence.c:29
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:169
#define CRM_XS
Definition: logging.h:55
char * pcmk__time_format_hr(const char *format, const pcmk__time_hr_t *hr_dt)
Definition: iso8601.c:1646
Cluster status and scheduling.
lrmd_api_operations_t * cmds
Definition: lrmd.h:598
#define crm_err(fmt, args...)
Definition: logging.h:359
#define RSC_STATUS
Definition: crm.h:213
Cluster Configuration.
Definition: lrmd.h:597
#define pcmk_ok
Definition: results.h:68
pcmk__alert_flags
char * value
Definition: lrmd.h:31
#define crm_info(fmt, args...)
Definition: logging.h:362
guint interval_ms
Definition: lrmd.h:232