pacemaker  2.0.2-debe490
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-2018 David Vossel <davidvossel@gmail.com>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #include <glib.h>
11 #include <unistd.h>
12 
13 #include <crm/crm.h>
14 #include <crm/msg_xml.h>
15 #include <crm/services.h>
16 #include <crm/common/mainloop.h>
20 
21 #include <crm/pengine/status.h>
22 #include <crm/cib.h>
23 #include <crm/lrmd.h>
24 
25 static lrmd_key_value_t *
26 alert_key2param(lrmd_key_value_t *head, enum crm_alert_keys_e name,
27  const char *value)
28 {
29  const char **key;
30 
31  if (value == NULL) {
32  value = "";
33  }
34  for (key = crm_alert_keys[name]; *key; key++) {
35  crm_trace("Setting alert key %s = '%s'", *key, value);
36  head = lrmd_key_value_add(head, *key, value);
37  }
38  return head;
39 }
40 
41 static lrmd_key_value_t *
42 alert_key2param_int(lrmd_key_value_t *head, enum crm_alert_keys_e name,
43  int value)
44 {
45  char *value_s = crm_itoa(value);
46 
47  head = alert_key2param(head, name, value_s);
48  free(value_s);
49  return head;
50 }
51 
52 static lrmd_key_value_t *
53 alert_key2param_ms(lrmd_key_value_t *head, enum crm_alert_keys_e name,
54  guint value)
55 {
56  char *value_s = crm_strdup_printf("%u", value);
57 
58  head = alert_key2param(head, name, value_s);
59  free(value_s);
60  return head;
61 }
62 
63 static void
64 set_ev_kv(gpointer key, gpointer value, gpointer user_data)
65 {
66  lrmd_key_value_t **head = (lrmd_key_value_t **) user_data;
67 
68  if (value) {
69  crm_trace("Setting environment variable %s='%s'",
70  (char*)key, (char*)value);
71  *head = lrmd_key_value_add(*head, key, value);
72  }
73 }
74 
75 static lrmd_key_value_t *
76 alert_envvar2params(lrmd_key_value_t *head, crm_alert_entry_t *entry)
77 {
78  if (entry->envvars) {
79  g_hash_table_foreach(entry->envvars, set_ev_kv, &head);
80  }
81  return head;
82 }
83 
84 /*
85  * We could use g_strv_contains() instead of this function,
86  * but that has only been available since glib 2.43.2.
87  */
88 static gboolean
89 is_target_alert(char **list, const char *value)
90 {
91  int target_list_num = 0;
92  gboolean rc = FALSE;
93 
94  CRM_CHECK(value != NULL, return FALSE);
95 
96  if (list == NULL) {
97  return TRUE;
98  }
99 
100  target_list_num = g_strv_length(list);
101 
102  for (int cnt = 0; cnt < target_list_num; cnt++) {
103  if (strcmp(list[cnt], value) == 0) {
104  rc = TRUE;
105  break;
106  }
107  }
108  return rc;
109 }
110 
125 static int
126 exec_alert_list(lrmd_t *lrmd, GList *alert_list, enum crm_alert_flags kind,
127  const char *attr_name, lrmd_key_value_t *params)
128 {
129  bool any_success = FALSE, any_failure = FALSE;
130  const char *kind_s = crm_alert_flag2text(kind);
131  crm_time_hr_t *now = NULL;
132  struct timeval tv_now;
133  char timestamp_epoch[20];
134  char timestamp_usec[7];
135 
136  params = alert_key2param(params, CRM_alert_kind, kind_s);
137  params = alert_key2param(params, CRM_alert_version, VERSION);
138 
139  for (GList *iter = g_list_first(alert_list); iter; iter = g_list_next(iter)) {
140  crm_alert_entry_t *entry = (crm_alert_entry_t *)(iter->data);
141  lrmd_key_value_t *copy_params = NULL;
142  lrmd_key_value_t *head = NULL;
143  int rc;
144 
145  if (is_not_set(entry->flags, kind)) {
146  crm_trace("Filtering unwanted %s alert to %s via %s",
147  kind_s, entry->recipient, entry->id);
148  continue;
149  }
150 
151  if ((kind == crm_alert_attribute)
152  && !is_target_alert(entry->select_attribute_name, attr_name)) {
153 
154  crm_trace("Filtering unwanted attribute '%s' alert to %s via %s",
155  attr_name, entry->recipient, entry->id);
156  continue;
157  }
158 
159  if (now == NULL) {
160  if (gettimeofday(&tv_now, NULL) == 0) {
161  now = crm_time_timeval_hr_convert(NULL, &tv_now);
162  }
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, CRM_alert_recipient,
173  entry->recipient);
174 
175  if (now) {
176  char *timestamp = crm_time_format_hr(entry->tstamp_format, now);
177 
178  if (timestamp) {
179  copy_params = alert_key2param(copy_params, CRM_alert_timestamp,
180  timestamp);
181  free(timestamp);
182  }
183 
184  snprintf(timestamp_epoch, sizeof(timestamp_epoch), "%lld",
185  (long long) tv_now.tv_sec);
186  copy_params = alert_key2param(copy_params, CRM_alert_timestamp_epoch, timestamp_epoch);
187  snprintf(timestamp_usec, sizeof(timestamp_usec), "%06d", now->useconds);
188  copy_params = alert_key2param(copy_params, CRM_alert_timestamp_usec, timestamp_usec);
189  }
190 
191  copy_params = alert_envvar2params(copy_params, entry);
192 
193  rc = lrmd->cmds->exec_alert(lrmd, entry->id, entry->path,
194  entry->timeout, copy_params);
195  if (rc < 0) {
196  crm_err("Could not execute alert %s: %s " CRM_XS " rc=%d",
197  entry->id, pcmk_strerror(rc), rc);
198  any_failure = TRUE;
199  } else {
200  any_success = TRUE;
201  }
202  }
203 
204  if (now) {
205  free(now);
206  }
207 
208  if (any_failure) {
209  return (any_success? -1 : -2);
210  }
211  return pcmk_ok;
212 }
213 
229 int
230 lrmd_send_attribute_alert(lrmd_t *lrmd, GList *alert_list,
231  const char *node, uint32_t nodeid,
232  const char *attr_name, const char *attr_value)
233 {
234  int rc = pcmk_ok;
235  lrmd_key_value_t *params = NULL;
236 
237  if (lrmd == NULL) {
238  return -2;
239  }
240 
241  params = alert_key2param(params, CRM_alert_node, node);
242  params = alert_key2param_int(params, CRM_alert_nodeid, nodeid);
243  params = alert_key2param(params, CRM_alert_attribute_name, attr_name);
244  params = alert_key2param(params, CRM_alert_attribute_value, attr_value);
245 
246  rc = exec_alert_list(lrmd, alert_list, crm_alert_attribute, attr_name,
247  params);
248  lrmd_key_value_freeall(params);
249  return rc;
250 }
251 
266 int
267 lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list,
268  const char *node, uint32_t nodeid, const char *state)
269 {
270  int rc = pcmk_ok;
271  lrmd_key_value_t *params = NULL;
272 
273  if (lrmd == NULL) {
274  return -2;
275  }
276 
277  params = alert_key2param(params, CRM_alert_node, node);
278  params = alert_key2param(params, CRM_alert_desc, state);
279  params = alert_key2param_int(params, CRM_alert_nodeid, nodeid);
280 
281  rc = exec_alert_list(lrmd, alert_list, crm_alert_node, NULL, params);
282  lrmd_key_value_freeall(params);
283  return rc;
284 }
285 
301 int
302 lrmd_send_fencing_alert(lrmd_t *lrmd, GList *alert_list,
303  const char *target, const char *task, const char *desc,
304  int op_rc)
305 {
306  int rc = pcmk_ok;
307  lrmd_key_value_t *params = NULL;
308 
309  if (lrmd == NULL) {
310  return -2;
311  }
312 
313  params = alert_key2param(params, CRM_alert_node, target);
314  params = alert_key2param(params, CRM_alert_task, task);
315  params = alert_key2param(params, CRM_alert_desc, desc);
316  params = alert_key2param_int(params, CRM_alert_rc, op_rc);
317 
318  rc = exec_alert_list(lrmd, alert_list, crm_alert_fencing, NULL, params);
319  lrmd_key_value_freeall(params);
320  return rc;
321 }
322 
336 int
337 lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list,
338  const char *node, lrmd_event_data_t *op)
339 {
340  int rc = pcmk_ok;
341  int target_rc = pcmk_ok;
342  lrmd_key_value_t *params = NULL;
343 
344  if (lrmd == NULL) {
345  return -2;
346  }
347 
348  target_rc = rsc_op_expected_rc(op);
349  if ((op->interval_ms == 0) && (target_rc == op->rc)
350  && safe_str_eq(op->op_type, RSC_STATUS)) {
351 
352  /* Don't send alerts for probes with the expected result. Leave it up to
353  * the agent whether to alert for 'failed' probes. (Even if we find a
354  * resource running, it was probably because someone did a clean-up of
355  * the status section.)
356  */
357  return pcmk_ok;
358  }
359 
360  params = alert_key2param(params, CRM_alert_node, node);
361  params = alert_key2param(params, CRM_alert_rsc, op->rsc_id);
362  params = alert_key2param(params, CRM_alert_task, op->op_type);
363  params = alert_key2param_ms(params, CRM_alert_interval, op->interval_ms);
364  params = alert_key2param_int(params, CRM_alert_target_rc, target_rc);
365  params = alert_key2param_int(params, CRM_alert_status, op->op_status);
366  params = alert_key2param_int(params, CRM_alert_rc, op->rc);
367 
368  /* Reoccurring operations do not set exec_time, so on timeout, set it
369  * to the operation timeout since that's closer to the actual value.
370  */
371  if (op->op_status == PCMK_LRM_OP_TIMEOUT && op->exec_time == 0) {
372  params = alert_key2param_int(params, CRM_alert_exec_time, op->timeout);
373  } else {
374  params = alert_key2param_int(params, CRM_alert_exec_time, op->exec_time);
375  }
376 
377  if (op->op_status == PCMK_LRM_OP_DONE) {
378  params = alert_key2param(params, CRM_alert_desc, services_ocf_exitcode_str(op->rc));
379  } else {
380  params = alert_key2param(params, CRM_alert_desc, services_lrm_status_str(op->op_status));
381  }
382 
383  rc = exec_alert_list(lrmd, alert_list, crm_alert_resource, NULL, params);
384  lrmd_key_value_freeall(params);
385  return rc;
386 }
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:156
A dumping ground.
const char * crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3]
Definition: alerts.c:19
const char * pcmk_strerror(int rc)
Definition: results.c:188
const char * rsc_id
Definition: lrmd.h:202
int lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list, const char *node, lrmd_event_data_t *op)
Definition: lrmd_alerts.c:337
GHashTable * envvars
int rsc_op_expected_rc(lrmd_event_data_t *event)
Definition: operations.c:376
char * recipient
#define VERSION
Definition: config.h:621
char * crm_time_format_hr(const char *format, crm_time_hr_t *hr_dt)
Definition: iso8601.c:1366
Resource agent executor.
enum ocf_exitcode rc
Definition: lrmd.h:220
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:504
uint32_t flags
unsigned int exec_time
Definition: lrmd.h:230
int lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list, const char *node, uint32_t nodeid, const char *state)
Definition: lrmd_alerts.c:267
char * tstamp_format
char * id
char * key
Definition: lrmd.h:28
#define crm_trace(fmt, args...)
Definition: logging.h:246
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *kvp, const char *key, const char *value)
Definition: lrmd_client.c:142
struct lrmd_key_value_s * next
Definition: lrmd.h:30
const char * op_type
Definition: lrmd.h:204
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:165
#define CRM_XS
Definition: logging.h:34
Cluster status and scheduling.
lrmd_api_operations_t * cmds
Definition: lrmd.h:533
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:302
crm_time_hr_t * crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
Definition: iso8601.c:1326
#define crm_err(fmt, args...)
Definition: logging.h:240
#define RSC_STATUS
Definition: crm.h:188
Cluster Configuration.
char ** select_attribute_name
int timeout
crm_alert_keys_e
char * path
Definition: lrmd.h:532
#define pcmk_ok
Definition: results.h:57
#define safe_str_eq(a, b)
Definition: util.h:59
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:230
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
crm_alert_flags
char * value
Definition: lrmd.h:29
#define crm_info(fmt, args...)
Definition: logging.h:243
guint interval_ms
Definition: lrmd.h:213