pacemaker  2.0.3-4b1f869f0f
Scalable High-Availability cluster resource manager
lrmd_alerts.c
Go to the documentation of this file.
1 /*
2  * Copyright 2015-2019 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 crm_alert_keys_e name,
29  const char *value)
30 {
31  const char **key;
32 
33  if (value == NULL) {
34  value = "";
35  }
36  for (key = crm_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 crm_alert_keys_e name,
45  int value)
46 {
47  char *value_s = crm_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 crm_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, crm_alert_entry_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 crm_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 = crm_alert_flag2text(kind);
133  crm_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, CRM_alert_kind, kind_s);
139  params = alert_key2param(params, CRM_alert_version, VERSION);
140 
141  for (GList *iter = g_list_first(alert_list); iter; iter = g_list_next(iter)) {
142  crm_alert_entry_t *entry = (crm_alert_entry_t *)(iter->data);
143  lrmd_key_value_t *copy_params = NULL;
144  lrmd_key_value_t *head = NULL;
145  int rc;
146 
147  if (is_not_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 == crm_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  if (gettimeofday(&tv_now, NULL) == 0) {
163  now = crm_time_timeval_hr_convert(NULL, &tv_now);
164  }
165  }
166  crm_info("Sending %s alert via %s to %s",
167  kind_s, entry->id, entry->recipient);
168 
169  /* Make a copy of the parameters, because each alert will be unique */
170  for (head = params; head != NULL; head = head->next) {
171  copy_params = lrmd_key_value_add(copy_params, head->key, head->value);
172  }
173 
174  copy_params = alert_key2param(copy_params, CRM_alert_recipient,
175  entry->recipient);
176 
177  if (now) {
178  char *timestamp = crm_time_format_hr(entry->tstamp_format, now);
179 
180  if (timestamp) {
181  copy_params = alert_key2param(copy_params, CRM_alert_timestamp,
182  timestamp);
183  free(timestamp);
184  }
185 
186  snprintf(timestamp_epoch, sizeof(timestamp_epoch), "%lld",
187  (long long) tv_now.tv_sec);
188  copy_params = alert_key2param(copy_params, CRM_alert_timestamp_epoch, timestamp_epoch);
189  snprintf(timestamp_usec, sizeof(timestamp_usec), "%06d", now->useconds);
190  copy_params = alert_key2param(copy_params, CRM_alert_timestamp_usec, 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 " CRM_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, 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, CRM_alert_node, node);
244  params = alert_key2param_int(params, CRM_alert_nodeid, nodeid);
245  params = alert_key2param(params, CRM_alert_attribute_name, attr_name);
246  params = alert_key2param(params, CRM_alert_attribute_value, attr_value);
247 
248  rc = exec_alert_list(lrmd, alert_list, crm_alert_attribute, attr_name,
249  params);
250  lrmd_key_value_freeall(params);
251  return rc;
252 }
253 
268 int
269 lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list,
270  const char *node, uint32_t nodeid, const char *state)
271 {
272  int rc = pcmk_ok;
273  lrmd_key_value_t *params = NULL;
274 
275  if (lrmd == NULL) {
276  return -2;
277  }
278 
279  params = alert_key2param(params, CRM_alert_node, node);
280  params = alert_key2param(params, CRM_alert_desc, state);
281  params = alert_key2param_int(params, CRM_alert_nodeid, nodeid);
282 
283  rc = exec_alert_list(lrmd, alert_list, crm_alert_node, NULL, params);
284  lrmd_key_value_freeall(params);
285  return rc;
286 }
287 
303 int
304 lrmd_send_fencing_alert(lrmd_t *lrmd, GList *alert_list,
305  const char *target, const char *task, const char *desc,
306  int op_rc)
307 {
308  int rc = pcmk_ok;
309  lrmd_key_value_t *params = NULL;
310 
311  if (lrmd == NULL) {
312  return -2;
313  }
314 
315  params = alert_key2param(params, CRM_alert_node, target);
316  params = alert_key2param(params, CRM_alert_task, task);
317  params = alert_key2param(params, CRM_alert_desc, desc);
318  params = alert_key2param_int(params, CRM_alert_rc, op_rc);
319 
320  rc = exec_alert_list(lrmd, alert_list, crm_alert_fencing, NULL, params);
321  lrmd_key_value_freeall(params);
322  return rc;
323 }
324 
338 int
339 lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list,
340  const char *node, lrmd_event_data_t *op)
341 {
342  int rc = pcmk_ok;
343  int target_rc = pcmk_ok;
344  lrmd_key_value_t *params = NULL;
345 
346  if (lrmd == NULL) {
347  return -2;
348  }
349 
350  target_rc = rsc_op_expected_rc(op);
351  if ((op->interval_ms == 0) && (target_rc == op->rc)
352  && safe_str_eq(op->op_type, RSC_STATUS)) {
353 
354  /* Don't send alerts for probes with the expected result. Leave it up to
355  * the agent whether to alert for 'failed' probes. (Even if we find a
356  * resource running, it was probably because someone did a clean-up of
357  * the status section.)
358  */
359  return pcmk_ok;
360  }
361 
362  params = alert_key2param(params, CRM_alert_node, node);
363  params = alert_key2param(params, CRM_alert_rsc, op->rsc_id);
364  params = alert_key2param(params, CRM_alert_task, op->op_type);
365  params = alert_key2param_ms(params, CRM_alert_interval, op->interval_ms);
366  params = alert_key2param_int(params, CRM_alert_target_rc, target_rc);
367  params = alert_key2param_int(params, CRM_alert_status, op->op_status);
368  params = alert_key2param_int(params, CRM_alert_rc, op->rc);
369 
370  /* Reoccurring operations do not set exec_time, so on timeout, set it
371  * to the operation timeout since that's closer to the actual value.
372  */
373  if (op->op_status == PCMK_LRM_OP_TIMEOUT && op->exec_time == 0) {
374  params = alert_key2param_int(params, CRM_alert_exec_time, op->timeout);
375  } else {
376  params = alert_key2param_int(params, CRM_alert_exec_time, op->exec_time);
377  }
378 
379  if (op->op_status == PCMK_LRM_OP_DONE) {
380  params = alert_key2param(params, CRM_alert_desc, services_ocf_exitcode_str(op->rc));
381  } else {
382  params = alert_key2param(params, CRM_alert_desc, services_lrm_status_str(op->op_status));
383  }
384 
385  rc = exec_alert_list(lrmd, alert_list, crm_alert_resource, NULL, params);
386  lrmd_key_value_freeall(params);
387  return rc;
388 }
crm_alert_entry_t::id
char * id
Definition: alerts_internal.h:32
lrmd_send_node_alert
int lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list, const char *node, uint32_t nodeid, const char *state)
Definition: lrmd_alerts.c:269
crm_alert_keys
const char * crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3]
Definition: alerts.c:19
CRM_alert_timestamp_epoch
Definition: alerts_internal.h:59
msg_xml.h
crm_alert_entry_t::select_attribute_name
char ** select_attribute_name
Definition: alerts_internal.h:36
lrmd_event_data_s::rc
enum ocf_exitcode rc
Definition: lrmd.h:221
lrmd_key_value_s::key
char * key
Definition: lrmd.h:29
CRM_alert_kind
Definition: alerts_internal.h:53
lrmd_s
Definition: lrmd.h:533
crm_time_us
Definition: iso8601_internal.h:38
pcmk_strerror
const char * pcmk_strerror(int rc)
Definition: results.c:188
crm_alert_attribute
Definition: alerts_internal.h:27
lrmd_send_attribute_alert
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:232
CRM_CHECK
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:157
crm_alert_entry_t
Definition: alerts_internal.h:31
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:241
crm_alert_node
Definition: alerts_internal.h:24
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:247
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:61
lrmd_key_value_add
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *kvp, const char *key, const char *value)
Definition: lrmd_client.c:142
CRM_alert_attribute_name
Definition: alerts_internal.h:57
CRM_alert_task
Definition: alerts_internal.h:47
lrmd_internal.h
PCMK_LRM_OP_TIMEOUT
Definition: services.h:123
crm_alert_entry_t::envvars
GHashTable * envvars
Definition: alerts_internal.h:37
mainloop.h
Wrappers for and extensions to glib mainloop.
lrmd_event_data_s::exec_time
unsigned int exec_time
Definition: lrmd.h:231
CRM_alert_node
Definition: alerts_internal.h:44
crm_alert_flags
crm_alert_flags
Definition: alerts_internal.h:22
crm_alert_entry_t::recipient
char * recipient
Definition: alerts_internal.h:35
lrmd_send_fencing_alert
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:304
crm_info
#define crm_info(fmt, args...)
Definition: logging.h:244
alerts_internal.h
CRM_alert_timestamp_usec
Definition: alerts_internal.h:60
crm_alert_entry_t::path
char * path
Definition: alerts_internal.h:33
lrmd_event_data_s::rsc_id
const char * rsc_id
Definition: lrmd.h:203
crm_time_format_hr
char * crm_time_format_hr(const char *format, crm_time_hr_t *hr_dt)
Definition: iso8601.c:1616
CRM_XS
#define CRM_XS
Definition: logging.h:34
lrmd_event_data_s
Definition: lrmd.h:198
CRM_alert_exec_time
Definition: alerts_internal.h:61
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
lrmd_event_data_s::op_type
const char * op_type
Definition: lrmd.h:205
crm_time_timeval_hr_convert
crm_time_hr_t * crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
Definition: iso8601.c:1576
rsc_op_expected_rc
int rsc_op_expected_rc(lrmd_event_data_t *event)
Definition: operations.c:332
lrmd_key_value_freeall
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:165
crm_alert_fencing
Definition: alerts_internal.h:25
crm_time_us::useconds
int useconds
Definition: iso8601_internal.h:45
lrmd_event_data_s::timeout
int timeout
Definition: lrmd.h:212
lrmd_event_data_s::op_status
int op_status
Definition: lrmd.h:223
crm_alert_entry_t::tstamp_format
char * tstamp_format
Definition: alerts_internal.h:34
lrmd_send_resource_alert
int lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list, const char *node, lrmd_event_data_t *op)
Definition: lrmd_alerts.c:339
CRM_alert_timestamp
Definition: alerts_internal.h:56
CRM_alert_attribute_value
Definition: alerts_internal.h:58
lrmd_api_operations_s::exec_alert
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:505
lrmd.h
Resource agent executor.
lrmd_key_value_s::next
struct lrmd_key_value_s * next
Definition: lrmd.h:31
CRM_alert_status
Definition: alerts_internal.h:50
CRM_alert_interval
Definition: alerts_internal.h:48
CRM_alert_version
Definition: alerts_internal.h:54
cib.h
Cluster Configuration.
RSC_STATUS
#define RSC_STATUS
Definition: crm.h:210
CRM_alert_recipient
Definition: alerts_internal.h:43
PCMK_LRM_OP_DONE
Definition: services.h:121
CRM_alert_rc
Definition: alerts_internal.h:52
services.h
Services API.
CRM_alert_rsc
Definition: alerts_internal.h:46
CRM_alert_desc
Definition: alerts_internal.h:49
crm_alert_entry_t::timeout
int timeout
Definition: alerts_internal.h:38
crm_alert_entry_t::flags
uint32_t flags
Definition: alerts_internal.h:39
lrmd_event_data_s::interval_ms
guint interval_ms
Definition: lrmd.h:214
CRM_alert_target_rc
Definition: alerts_internal.h:51
VERSION
#define VERSION
Definition: config.h:627
iso8601_internal.h
crm_alert_resource
Definition: alerts_internal.h:26
lrmd_key_value_s
Definition: lrmd.h:28
crm_alert_keys_e
crm_alert_keys_e
Definition: alerts_internal.h:42
crm_internal.h
CRM_alert_nodeid
Definition: alerts_internal.h:45
status.h
Cluster status and scheduling.
crm.h
A dumping ground.
lrmd_s::cmds
lrmd_api_operations_t * cmds
Definition: lrmd.h:534
pcmk_ok
#define pcmk_ok
Definition: results.h:57
lrmd_key_value_s::value
char * value
Definition: lrmd.h:30