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