pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
27 static lrmd_key_value_t *
28 alert_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 
43 static lrmd_key_value_t *
44 alert_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 
54 static lrmd_key_value_t *
55 alert_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 
65 static void
66 set_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 
77 static lrmd_key_value_t *
78 alert_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  */
90 static gboolean
91 is_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 
127 static int
128 exec_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 
237 int
238 lrmd_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);
257  lrmd_key_value_freeall(params);
258  return rc;
259 }
260 
275 int
276 lrmd_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);
291  lrmd_key_value_freeall(params);
292  return rc;
293 }
294 
310 int
311 lrmd_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);
328  lrmd_key_value_freeall(params);
329  return rc;
330 }
331 
345 int
346 lrmd_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);
398  lrmd_key_value_freeall(params);
399  return rc;
400 }
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:58
int lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list, const char *node, lrmd_event_data_t *op)
Definition: lrmd_alerts.c:346
const char * rsc_id
Definition: lrmd.h:203
pcmk__time_hr_t * pcmk__time_timeval_hr_convert(pcmk__time_hr_t *target, struct timeval *tv)
Definition: iso8601.c:1591
int rsc_op_expected_rc(lrmd_event_data_t *event)
Definition: operations.c:426
char ** select_attribute_name
char * tstamp_format
Resource agent executor.
enum ocf_exitcode rc
Definition: lrmd.h:221
pcmk__alert_keys_e
#define PACEMAKER_VERSION
Definition: config.h:478
char * pcmk__time_format_hr(const char *format, pcmk__time_hr_t *hr_dt)
Definition: iso8601.c:1631
Wrappers for and extensions to glib mainloop.
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
unsigned int exec_time
Definition: lrmd.h:231
const char * pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX][3]
Definition: alerts.c:22
int lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list, const char *node, uint32_t nodeid, const char *state)
Definition: lrmd_alerts.c:276
int rc
Definition: pcmk_fence.c:35
char * key
Definition: lrmd.h:29
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:238
#define crm_trace(fmt, args...)
Definition: logging.h:356
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
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *kvp, const char *key, const char *value)
Definition: lrmd_client.c:145
struct lrmd_key_value_s * next
Definition: lrmd.h:31
GHashTable * envvars
const char * op_type
Definition: lrmd.h:205
const char * target
Definition: pcmk_fence.c:29
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:168
#define CRM_XS
Definition: logging.h:54
Cluster status and scheduling.
lrmd_api_operations_t * cmds
Definition: lrmd.h:511
#define crm_err(fmt, args...)
Definition: logging.h:350
#define RSC_STATUS
Definition: crm.h:215
Cluster Configuration.
Definition: lrmd.h:510
#define pcmk_ok
Definition: results.h:67
char * name
Definition: pcmk_fence.c:31
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:311
pcmk__alert_flags
char * value
Definition: lrmd.h:30
#define crm_info(fmt, args...)
Definition: logging.h:353
guint interval_ms
Definition: lrmd.h:214