pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmk_sched_notif.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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 General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <crm/msg_xml.h>
12 #include <pacemaker-internal.h>
13 
14 typedef struct notify_entry_s {
15  pe_resource_t *rsc;
16  pe_node_t *node;
18 
19 static gint
20 sort_notify_entries(gconstpointer a, gconstpointer b)
21 {
22  int tmp;
23  const notify_entry_t *entry_a = a;
24  const notify_entry_t *entry_b = b;
25 
26  if (entry_a == NULL && entry_b == NULL) {
27  return 0;
28  }
29  if (entry_a == NULL) {
30  return 1;
31  }
32  if (entry_b == NULL) {
33  return -1;
34  }
35 
36  if (entry_a->rsc == NULL && entry_b->rsc == NULL) {
37  return 0;
38  }
39  if (entry_a->rsc == NULL) {
40  return 1;
41  }
42  if (entry_b->rsc == NULL) {
43  return -1;
44  }
45 
46  tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
47  if (tmp != 0) {
48  return tmp;
49  }
50 
51  if (entry_a->node == NULL && entry_b->node == NULL) {
52  return 0;
53  }
54  if (entry_a->node == NULL) {
55  return 1;
56  }
57  if (entry_b->node == NULL) {
58  return -1;
59  }
60 
61  return strcmp(entry_a->node->details->id, entry_b->node->details->id);
62 }
63 
64 static notify_entry_t *dup_notify_entry(notify_entry_t *entry)
65 {
66  notify_entry_t *dup = malloc(sizeof(notify_entry_t));
67 
68  CRM_ASSERT(dup != NULL);
69  dup->rsc = entry->rsc;
70  dup->node = entry->node;
71  return dup;
72 }
73 
74 static void
75 expand_node_list(GListPtr list, char **uname, char **metal)
76 {
77  GListPtr gIter = NULL;
78  char *node_list = NULL;
79  char *metal_list = NULL;
80 
81  CRM_ASSERT(uname != NULL);
82  if (list == NULL) {
83  *uname = strdup(" ");
84  if(metal) {
85  *metal = strdup(" ");
86  }
87  return;
88  }
89 
90  for (gIter = list; gIter != NULL; gIter = gIter->next) {
91  int len = 0;
92  int existing_len = 0;
93  pe_node_t *node = (pe_node_t *) gIter->data;
94 
95  if (node->details->uname == NULL) {
96  continue;
97  }
98  len = 2 + strlen(node->details->uname);
99 
100  if(node_list) {
101  existing_len = strlen(node_list);
102  }
103 // crm_trace("Adding %s (%dc) at offset %d", node->details->uname, len - 2, existing_len);
104  node_list = realloc_safe(node_list, len + existing_len);
105  sprintf(node_list + existing_len, "%s%s", existing_len == 0 ? "":" ", node->details->uname);
106 
107  if(metal) {
108  existing_len = 0;
109  if(metal_list) {
110  existing_len = strlen(metal_list);
111  }
112 
113  if(node->details->remote_rsc
114  && node->details->remote_rsc->container
115  && node->details->remote_rsc->container->running_on) {
116  node = pe__current_node(node->details->remote_rsc->container);
117  }
118 
119  if (node->details->uname == NULL) {
120  continue;
121  }
122  len = 2 + strlen(node->details->uname);
123  metal_list = realloc_safe(metal_list, len + existing_len);
124  sprintf(metal_list + existing_len, "%s%s", existing_len == 0 ? "":" ", node->details->uname);
125  }
126  }
127 
128  *uname = node_list;
129  if(metal) {
130  *metal = metal_list;
131  }
132 }
133 
134 static void
135 expand_list(GListPtr list, char **rsc_list, char **node_list)
136 {
137  GListPtr gIter = NULL;
138  const char *uname = NULL;
139  const char *rsc_id = NULL;
140  const char *last_rsc_id = NULL;
141 
142  if (rsc_list) {
143  *rsc_list = NULL;
144  }
145 
146  if (list == NULL) {
147  if (rsc_list) {
148  *rsc_list = strdup(" ");
149  }
150  if (node_list) {
151  *node_list = strdup(" ");
152  }
153  return;
154  }
155 
156  if (node_list) {
157  *node_list = NULL;
158  }
159 
160  for (gIter = list; gIter != NULL; gIter = gIter->next) {
161  notify_entry_t *entry = (notify_entry_t *) gIter->data;
162 
163  CRM_LOG_ASSERT(entry != NULL);
164  CRM_LOG_ASSERT(entry && entry->rsc != NULL);
165 
166  if(entry == NULL || entry->rsc == NULL) {
167  continue;
168  }
169 
170  /* Uh, why? */
171  CRM_LOG_ASSERT(node_list == NULL || entry->node != NULL);
172  if(node_list != NULL && entry->node == NULL) {
173  continue;
174  }
175 
176  uname = NULL;
177  rsc_id = entry->rsc->id;
178  CRM_ASSERT(rsc_id != NULL);
179 
180  /* filter dups */
181  if (safe_str_eq(rsc_id, last_rsc_id)) {
182  continue;
183  }
184  last_rsc_id = rsc_id;
185 
186  if (rsc_list != NULL) {
187  int existing_len = 0;
188  int len = 2 + strlen(rsc_id); /* +1 space, +1 EOS */
189 
190  if (*rsc_list) {
191  existing_len = strlen(*rsc_list);
192  }
193 
194  crm_trace("Adding %s (%dc) at offset %d", rsc_id, len - 2, existing_len);
195  *rsc_list = realloc_safe(*rsc_list, len + existing_len);
196  sprintf(*rsc_list + existing_len, "%s%s", existing_len == 0 ? "":" ", rsc_id);
197  }
198 
199  if (entry->node != NULL) {
200  uname = entry->node->details->uname;
201  }
202 
203  if (node_list != NULL && uname) {
204  int existing_len = 0;
205  int len = 2 + strlen(uname);
206 
207  if (*node_list) {
208  existing_len = strlen(*node_list);
209  }
210 
211  crm_trace("Adding %s (%dc) at offset %d", uname, len - 2, existing_len);
212  *node_list = realloc_safe(*node_list, len + existing_len);
213  sprintf(*node_list + existing_len, "%s%s", existing_len == 0 ? "":" ", uname);
214  }
215  }
216 
217 }
218 
219 static void
220 dup_attr(gpointer key, gpointer value, gpointer user_data)
221 {
222  add_hash_param(user_data, key, value);
223 }
224 
225 static void
226 add_notify_data_to_action_meta(notify_data_t *n_data, pe_action_t *action)
227 {
228  for (GSList *item = n_data->keys; item; item = item->next) {
229  pcmk_nvpair_t *nvpair = item->data;
230 
231  add_hash_param(action->meta, nvpair->name, nvpair->value);
232  }
233 }
234 
235 static pe_action_t *
236 pe_notify(pe_resource_t * rsc, pe_node_t * node, pe_action_t * op, pe_action_t * confirm,
237  notify_data_t * n_data, pe_working_set_t * data_set)
238 {
239  char *key = NULL;
240  pe_action_t *trigger = NULL;
241  const char *value = NULL;
242  const char *task = NULL;
243 
244  if (op == NULL || confirm == NULL) {
245  pe_rsc_trace(rsc, "Op=%p confirm=%p", op, confirm);
246  return NULL;
247  }
248 
249  CRM_CHECK(rsc != NULL, return NULL);
250  CRM_CHECK(node != NULL, return NULL);
251 
252  if (node->details->online == FALSE) {
253  pe_rsc_trace(rsc, "Skipping notification for %s: node offline", rsc->id);
254  return NULL;
255  } else if (is_set(op->flags, pe_action_runnable) == FALSE) {
256  pe_rsc_trace(rsc, "Skipping notification for %s: not runnable", op->uuid);
257  return NULL;
258  }
259 
260  value = g_hash_table_lookup(op->meta, "notify_type");
261  task = g_hash_table_lookup(op->meta, "notify_operation");
262 
263  pe_rsc_trace(rsc, "Creating notify actions for %s: %s (%s-%s)", op->uuid, rsc->id, value, task);
264 
265  key = pcmk__notify_key(rsc->id, value, task);
266  trigger = custom_action(rsc, key, op->task, node,
267  is_set(op->flags, pe_action_optional), TRUE, data_set);
268  g_hash_table_foreach(op->meta, dup_attr, trigger->meta);
269  add_notify_data_to_action_meta(n_data, trigger);
270 
271  /* pseudo_notify before notify */
272  pe_rsc_trace(rsc, "Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id,
273  op->id);
274 
275  order_actions(op, trigger, pe_order_optional);
276  order_actions(trigger, confirm, pe_order_optional);
277  return trigger;
278 }
279 
280 static void
281 pe_post_notify(pe_resource_t * rsc, pe_node_t * node, notify_data_t * n_data, pe_working_set_t * data_set)
282 {
283  pe_action_t *notify = NULL;
284 
285  CRM_CHECK(rsc != NULL, return);
286 
287  if (n_data->post == NULL) {
288  return; /* Nothing to do */
289  }
290 
291  notify = pe_notify(rsc, node, n_data->post, n_data->post_done, n_data, data_set);
292 
293  if (notify != NULL) {
294  notify->priority = INFINITY;
295  }
296 
297  if (n_data->post_done) {
298  GListPtr gIter = rsc->actions;
299 
300  for (; gIter != NULL; gIter = gIter->next) {
301  pe_action_t *mon = (pe_action_t *) gIter->data;
302  const char *interval_ms_s = g_hash_table_lookup(mon->meta,
304 
305  if ((interval_ms_s == NULL) || safe_str_eq(interval_ms_s, "0")) {
306  pe_rsc_trace(rsc, "Skipping %s: interval", mon->uuid);
307  continue;
308  } else if (safe_str_eq(mon->task, RSC_CANCEL)) {
309  pe_rsc_trace(rsc, "Skipping %s: cancel", mon->uuid);
310  continue;
311  }
312 
314  }
315  }
316 }
317 
319 create_notification_boundaries(pe_resource_t * rsc, const char *action, pe_action_t * start,
320  pe_action_t * end, pe_working_set_t * data_set)
321 {
322  /* Create the pseudo ops that precede and follow the actual notifications */
323 
324  /*
325  * Creates two sequences (conditional on start and end being supplied):
326  * pre_notify -> pre_notify_complete -> start, and
327  * end -> post_notify -> post_notify_complete
328  *
329  * 'start' and 'end' may be the same event or ${X} and ${X}ed as per clones
330  */
331  char *key = NULL;
332  notify_data_t *n_data = NULL;
333 
334  if (is_not_set(rsc->flags, pe_rsc_notify)) {
335  return NULL;
336  }
337 
338  n_data = calloc(1, sizeof(notify_data_t));
339  n_data->action = action;
340 
341  if (start) {
342  /* create pre-event notification wrappers */
343  key = pcmk__notify_key(rsc->id, "pre", start->task);
344  n_data->pre =
345  custom_action(rsc, key, RSC_NOTIFY, NULL, is_set(start->flags, pe_action_optional),
346  TRUE, data_set);
347 
348  update_action_flags(n_data->pre, pe_action_pseudo, __FUNCTION__, __LINE__);
349  update_action_flags(n_data->pre, pe_action_runnable, __FUNCTION__, __LINE__);
350 
351  add_hash_param(n_data->pre->meta, "notify_type", "pre");
352  add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
353 
354  add_hash_param(n_data->pre->meta, "notify_key_type", "pre");
355  add_hash_param(n_data->pre->meta, "notify_key_operation", start->task);
356 
357  /* create pre_notify_complete */
358  key = pcmk__notify_key(rsc->id, "confirmed-pre", start->task);
359  n_data->pre_done =
360  custom_action(rsc, key, RSC_NOTIFIED, NULL, is_set(start->flags, pe_action_optional),
361  TRUE, data_set);
362 
363  update_action_flags(n_data->pre_done, pe_action_pseudo, __FUNCTION__, __LINE__);
364  update_action_flags(n_data->pre_done, pe_action_runnable, __FUNCTION__, __LINE__);
365 
366  add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
367  add_hash_param(n_data->pre_done->meta, "notify_operation", n_data->action);
368 
369  add_hash_param(n_data->pre_done->meta, "notify_key_type", "confirmed-pre");
370  add_hash_param(n_data->pre_done->meta, "notify_key_operation", start->task);
371 
372  order_actions(n_data->pre_done, start, pe_order_optional);
373  order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
374  }
375 
376  if (end) {
377  /* create post-event notification wrappers */
378  key = pcmk__notify_key(rsc->id, "post", end->task);
379  n_data->post =
380  custom_action(rsc, key, RSC_NOTIFY, NULL, is_set(end->flags, pe_action_optional), TRUE,
381  data_set);
382 
383  n_data->post->priority = INFINITY;
384  update_action_flags(n_data->post, pe_action_pseudo, __FUNCTION__, __LINE__);
385  if (is_set(end->flags, pe_action_runnable)) {
386  update_action_flags(n_data->post, pe_action_runnable, __FUNCTION__, __LINE__);
387  } else {
388  update_action_flags(n_data->post, pe_action_runnable | pe_action_clear, __FUNCTION__, __LINE__);
389  }
390 
391  add_hash_param(n_data->post->meta, "notify_type", "post");
392  add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
393 
394  add_hash_param(n_data->post->meta, "notify_key_type", "post");
395  add_hash_param(n_data->post->meta, "notify_key_operation", end->task);
396 
397  /* create post_notify_complete */
398  key = pcmk__notify_key(rsc->id, "confirmed-post", end->task);
399  n_data->post_done =
400  custom_action(rsc, key, RSC_NOTIFIED, NULL, is_set(end->flags, pe_action_optional),
401  TRUE, data_set);
402 
403  n_data->post_done->priority = INFINITY;
404  update_action_flags(n_data->post_done, pe_action_pseudo, __FUNCTION__, __LINE__);
405  if (is_set(end->flags, pe_action_runnable)) {
406  update_action_flags(n_data->post_done, pe_action_runnable, __FUNCTION__, __LINE__);
407  } else {
408  update_action_flags(n_data->post_done, pe_action_runnable | pe_action_clear, __FUNCTION__, __LINE__);
409  }
410 
411  add_hash_param(n_data->post_done->meta, "notify_type", "post");
412  add_hash_param(n_data->post_done->meta, "notify_operation", n_data->action);
413 
414  add_hash_param(n_data->post_done->meta, "notify_key_type", "confirmed-post");
415  add_hash_param(n_data->post_done->meta, "notify_key_operation", end->task);
416 
419  }
420 
421  if (start && end) {
422  order_actions(n_data->pre_done, n_data->post, pe_order_optional);
423  }
424  return n_data;
425 }
426 
427 void
428 collect_notification_data(pe_resource_t * rsc, gboolean state, gboolean activity,
429  notify_data_t * n_data)
430 {
431 
432  if(n_data->allowed_nodes == NULL) {
433  n_data->allowed_nodes = rsc->allowed_nodes;
434  }
435 
436  if (rsc->children) {
437  GListPtr gIter = rsc->children;
438 
439  for (; gIter != NULL; gIter = gIter->next) {
440  pe_resource_t *child = (pe_resource_t *) gIter->data;
441 
442  collect_notification_data(child, state, activity, n_data);
443  }
444  return;
445  }
446 
447  if (state) {
448  notify_entry_t *entry = NULL;
449 
450  entry = calloc(1, sizeof(notify_entry_t));
451  entry->rsc = rsc;
452  if (rsc->running_on) {
453  /* we only take the first one */
454  entry->node = rsc->running_on->data;
455  }
456 
457  pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(rsc->role));
458 
459  switch (rsc->role) {
460  case RSC_ROLE_STOPPED:
461  n_data->inactive = g_list_prepend(n_data->inactive, entry);
462  break;
463  case RSC_ROLE_STARTED:
464  n_data->active = g_list_prepend(n_data->active, entry);
465  break;
466  case RSC_ROLE_SLAVE:
467  n_data->slave = g_list_prepend(n_data->slave, entry);
468  n_data->active = g_list_prepend(n_data->active,
469  dup_notify_entry(entry));
470  break;
471  case RSC_ROLE_MASTER:
472  n_data->master = g_list_prepend(n_data->master, entry);
473  n_data->active = g_list_prepend(n_data->active,
474  dup_notify_entry(entry));
475  break;
476  default:
477  crm_err("Unsupported notify role");
478  free(entry);
479  break;
480  }
481  }
482 
483  if (activity) {
484  notify_entry_t *entry = NULL;
485  enum action_tasks task;
486 
487  GListPtr gIter = rsc->actions;
488 
489  for (; gIter != NULL; gIter = gIter->next) {
490  pe_action_t *op = (pe_action_t *) gIter->data;
491 
492  if (is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) {
493  task = text2task(op->task);
494 
495  if(task == stop_rsc && op->node->details->unclean) {
496  // Create anyway (additional noise if node can't be fenced)
497  } else if(is_not_set(op->flags, pe_action_runnable)) {
498  continue;
499  }
500 
501  entry = calloc(1, sizeof(notify_entry_t));
502  entry->node = op->node;
503  entry->rsc = rsc;
504 
505  switch (task) {
506  case start_rsc:
507  n_data->start = g_list_prepend(n_data->start, entry);
508  break;
509  case stop_rsc:
510  n_data->stop = g_list_prepend(n_data->stop, entry);
511  break;
512  case action_promote:
513  n_data->promote = g_list_prepend(n_data->promote, entry);
514  break;
515  case action_demote:
516  n_data->demote = g_list_prepend(n_data->demote, entry);
517  break;
518  default:
519  free(entry);
520  break;
521  }
522  }
523  }
524  }
525 }
526 
527 #define add_notify_env(n_data, key, value) do { \
528  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
529  } while (0)
530 
531 #define add_notify_env_free(n_data, key, value) do { \
532  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
533  free(value); value = NULL; \
534  } while (0)
535 
536 gboolean
538 {
539  /* Expand the notification entries into a key=value hashtable
540  * This hashtable is later used in action2xml()
541  */
542  gboolean required = FALSE;
543  char *rsc_list = NULL;
544  char *node_list = NULL;
545  char *metal_list = NULL;
546  const char *source = NULL;
547  GListPtr nodes = NULL;
548 
549  if (n_data->stop) {
550  n_data->stop = g_list_sort(n_data->stop, sort_notify_entries);
551  }
552  expand_list(n_data->stop, &rsc_list, &node_list);
553  if (rsc_list != NULL && safe_str_neq(" ", rsc_list)) {
554  if (safe_str_eq(n_data->action, RSC_STOP)) {
555  required = TRUE;
556  }
557  }
558  add_notify_env_free(n_data, "notify_stop_resource", rsc_list);
559  add_notify_env_free(n_data, "notify_stop_uname", node_list);
560 
561  if (n_data->start) {
562  n_data->start = g_list_sort(n_data->start, sort_notify_entries);
563  if (rsc_list && safe_str_eq(n_data->action, RSC_START)) {
564  required = TRUE;
565  }
566  }
567  expand_list(n_data->start, &rsc_list, &node_list);
568  add_notify_env_free(n_data, "notify_start_resource", rsc_list);
569  add_notify_env_free(n_data, "notify_start_uname", node_list);
570 
571  if (n_data->demote) {
572  n_data->demote = g_list_sort(n_data->demote, sort_notify_entries);
573  if (safe_str_eq(n_data->action, RSC_DEMOTE)) {
574  required = TRUE;
575  }
576  }
577 
578  expand_list(n_data->demote, &rsc_list, &node_list);
579  add_notify_env_free(n_data, "notify_demote_resource", rsc_list);
580  add_notify_env_free(n_data, "notify_demote_uname", node_list);
581 
582  if (n_data->promote) {
583  n_data->promote = g_list_sort(n_data->promote, sort_notify_entries);
584  if (safe_str_eq(n_data->action, RSC_PROMOTE)) {
585  required = TRUE;
586  }
587  }
588  expand_list(n_data->promote, &rsc_list, &node_list);
589  add_notify_env_free(n_data, "notify_promote_resource", rsc_list);
590  add_notify_env_free(n_data, "notify_promote_uname", node_list);
591 
592  if (n_data->active) {
593  n_data->active = g_list_sort(n_data->active, sort_notify_entries);
594  }
595  expand_list(n_data->active, &rsc_list, &node_list);
596  add_notify_env_free(n_data, "notify_active_resource", rsc_list);
597  add_notify_env_free(n_data, "notify_active_uname", node_list);
598 
599  if (n_data->slave) {
600  n_data->slave = g_list_sort(n_data->slave, sort_notify_entries);
601  }
602  expand_list(n_data->slave, &rsc_list, &node_list);
603  add_notify_env_free(n_data, "notify_slave_resource", rsc_list);
604  add_notify_env_free(n_data, "notify_slave_uname", node_list);
605 
606  if (n_data->master) {
607  n_data->master = g_list_sort(n_data->master, sort_notify_entries);
608  }
609  expand_list(n_data->master, &rsc_list, &node_list);
610  add_notify_env_free(n_data, "notify_master_resource", rsc_list);
611  add_notify_env_free(n_data, "notify_master_uname", node_list);
612 
613  if (n_data->inactive) {
614  n_data->inactive = g_list_sort(n_data->inactive, sort_notify_entries);
615  }
616  expand_list(n_data->inactive, &rsc_list, NULL);
617  add_notify_env_free(n_data, "notify_inactive_resource", rsc_list);
618 
619  nodes = g_hash_table_get_values(n_data->allowed_nodes);
620  if (is_set(data_set->flags, pe_flag_stdout)) {
621  /* If printing to stdout, sort the node list, for consistent
622  * regression test output (while avoiding the performance hit
623  * for the live cluster).
624  */
625  nodes = g_list_sort(nodes, sort_node_uname);
626  }
627  expand_node_list(nodes, &node_list, NULL);
628  add_notify_env_free(n_data, "notify_available_uname", node_list);
629  g_list_free(nodes);
630 
631  source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
632  if (safe_str_eq("host", source)) {
633  expand_node_list(data_set->nodes, &node_list, &metal_list);
634  add_notify_env_free(n_data, "notify_all_hosts", metal_list);
635  } else {
636  expand_node_list(data_set->nodes, &node_list, NULL);
637  }
638  add_notify_env_free(n_data, "notify_all_uname", node_list);
639 
640  if (required && n_data->pre) {
641  update_action_flags(n_data->pre, pe_action_optional | pe_action_clear, __FUNCTION__, __LINE__);
642  update_action_flags(n_data->pre_done, pe_action_optional | pe_action_clear, __FUNCTION__, __LINE__);
643  }
644 
645  if (required && n_data->post) {
646  update_action_flags(n_data->post, pe_action_optional | pe_action_clear, __FUNCTION__, __LINE__);
647  update_action_flags(n_data->post_done, pe_action_optional | pe_action_clear, __FUNCTION__, __LINE__);
648  }
649  return required;
650 }
651 
652 /*
653  * \internal
654  * \brief Find any remote connection start relevant to an action
655  *
656  * \param[in] action Action to chek
657  *
658  * \return If action is behind a remote connection, connection's start
659  */
660 static pe_action_t *
661 find_remote_start(pe_action_t *action)
662 {
663  if (action && action->node) {
664  pe_resource_t *remote_rsc = action->node->details->remote_rsc;
665 
666  if (remote_rsc) {
667  return find_first_action(remote_rsc->actions, NULL, RSC_START,
668  NULL);
669  }
670  }
671  return NULL;
672 }
673 
674 void
676 {
677  GListPtr gIter = NULL;
678  pe_action_t *stop = NULL;
679  pe_action_t *start = NULL;
680  enum action_tasks task = text2task(n_data->action);
681 
682  if (rsc->children) {
683  gIter = rsc->children;
684  for (; gIter != NULL; gIter = gIter->next) {
685  pe_resource_t *child = (pe_resource_t *) gIter->data;
686 
687  create_notifications(child, n_data, data_set);
688  }
689  return;
690  }
691 
692  /* Copy notification details into standard ops */
693 
694  for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
695  pe_action_t *op = (pe_action_t *) gIter->data;
696 
697  if (is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) {
698  enum action_tasks t = text2task(op->task);
699 
700  switch (t) {
701  case start_rsc:
702  case stop_rsc:
703  case action_promote:
704  case action_demote:
705  add_notify_data_to_action_meta(n_data, op);
706  break;
707  default:
708  break;
709  }
710  }
711  }
712 
713  switch (task) {
714  case start_rsc:
715  if (n_data->start == NULL) {
716  pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
717  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
718  return;
719  }
720  break;
721  case action_promote:
722  if (n_data->promote == NULL) {
723  pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
724  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
725  return;
726  }
727  break;
728  case action_demote:
729  if (n_data->demote == NULL) {
730  pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
731  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
732  return;
733  }
734  break;
735  default:
736  /* We cannot do the same for stop_rsc/n_data->stop at it
737  * might be implied by fencing
738  */
739  break;
740  }
741 
742  pe_rsc_trace(rsc, "Creating notifications for: %s.%s (%s->%s)",
743  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
744 
745  stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
746  start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
747 
748  /* stop / demote */
749  if (rsc->role != RSC_ROLE_STOPPED) {
750  if (task == stop_rsc || task == action_demote) {
751  gIter = rsc->running_on;
752  for (; gIter != NULL; gIter = gIter->next) {
753  pe_node_t *current_node = (pe_node_t *) gIter->data;
754 
755  /* if this stop action is a pseudo action as a result of the current
756  * node being fenced, this stop action is implied by the fencing
757  * action. There's no reason to send the fenced node a stop notification */
758  if (stop &&
759  is_set(stop->flags, pe_action_pseudo) &&
760  (current_node->details->unclean || current_node->details->remote_requires_reset) ) {
761 
762  continue;
763  }
764 
765  pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set);
766  if (task == action_demote || stop == NULL
767  || is_set(stop->flags, pe_action_optional)) {
768  pe_post_notify(rsc, current_node, n_data, data_set);
769  }
770  }
771  }
772  }
773 
774  /* start / promote */
775  if (rsc->next_role != RSC_ROLE_STOPPED) {
776  if (rsc->allocated_to == NULL) {
777  pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role),
778  rsc->id);
779 
780  } else if (task == start_rsc || task == action_promote) {
781 
782  if (start) {
783  pe_action_t *remote_start = find_remote_start(start);
784 
785  if (remote_start
786  && is_not_set(remote_start->flags, pe_action_runnable)) {
787  /* Start and promote actions for a clone instance behind
788  * a Pacemaker Remote connection happen after the
789  * connection starts. If the connection start is blocked, do
790  * not schedule notifications for these actions.
791  */
792  return;
793  }
794  }
795  if (task != start_rsc || start == NULL || is_set(start->flags, pe_action_optional)) {
796  pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set);
797  }
798  pe_post_notify(rsc, rsc->allocated_to, n_data, data_set);
799  }
800  }
801 }
802 
803 void
805 {
806  if (n_data == NULL) {
807  return;
808  }
809 
810  g_list_free_full(n_data->stop, free);
811  g_list_free_full(n_data->start, free);
812  g_list_free_full(n_data->demote, free);
813  g_list_free_full(n_data->promote, free);
814  g_list_free_full(n_data->master, free);
815  g_list_free_full(n_data->slave, free);
816  g_list_free_full(n_data->active, free);
817  g_list_free_full(n_data->inactive, free);
818  pcmk_free_nvpairs(n_data->keys);
819  free(n_data);
820 }
821 
822 void
824  pe_action_t *stonith_op,
825  pe_working_set_t *data_set)
826 {
827  notify_data_t *n_data;
828 
829  crm_info("Creating secondary notification for %s", action->uuid);
830  n_data = create_notification_boundaries(rsc, RSC_STOP, NULL, stonith_op,
831  data_set);
832  collect_notification_data(rsc, TRUE, FALSE, n_data);
833  add_notify_env(n_data, "notify_stop_resource", rsc->id);
834  add_notify_env(n_data, "notify_stop_uname", action->node->details->uname);
835  create_notifications(uber_parent(rsc), n_data, data_set);
836  free_notification_data(n_data);
837 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
char uname[MAX_NAME]
Definition: internal.h:85
GListPtr nodes
Definition: pe_types.h:146
#define RSC_STOP
Definition: crm.h:199
char * name
Definition: nvpair.h:29
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:263
#define INFINITY
Definition: crm.h:95
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:102
GHashTable * allowed_nodes
Definition: internal.h:95
int priority
Definition: pe_types.h:386
pe_resource_t * container
Definition: pe_types.h:364
char * value
Definition: nvpair.h:30
enum rsc_role_e role
Definition: pe_types.h:354
#define RSC_NOTIFIED
Definition: crm.h:208
void collect_notification_data(pe_resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data)
enum rsc_role_e next_role
Definition: pe_types.h:355
GListPtr slave
Definition: internal.h:94
pe_resource_t * remote_rsc
Definition: pe_types.h:217
GHashTable * meta
Definition: pe_types.h:357
#define pe_rsc_notify
Definition: pe_types.h:240
void create_notifications(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
enum action_tasks text2task(const char *task)
Definition: common.c:358
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
#define RSC_START
Definition: crm.h:196
pe_node_t * allocated_to
Definition: pe_types.h:347
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:182
#define pe_proc_err(fmt...)
Definition: internal.h:23
gboolean remote_requires_reset
Definition: pe_types.h:211
#define RSC_NOTIFY
Definition: crm.h:207
const char * action
Definition: pcmk_fence.c:29
notify_data_t * create_notification_boundaries(pe_resource_t *rsc, const char *action, pe_action_t *start, pe_action_t *end, pe_working_set_t *data_set)
void free_notification_data(notify_data_t *n_data)
const char * role2text(enum rsc_role_e role)
Definition: common.c:463
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:129
GListPtr stop
Definition: internal.h:90
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:762
pe_action_t * post
Definition: internal.h:83
#define add_notify_env_free(n_data, key, value)
char * task
Definition: pe_types.h:392
#define crm_trace(fmt, args...)
Definition: logging.h:369
GListPtr master
Definition: internal.h:93
GHashTable * meta
Definition: pe_types.h:402
struct pe_node_shared_s * details
Definition: pe_types.h:231
GListPtr running_on
Definition: pe_types.h:350
pe_node_t * node
Definition: pe_types.h:389
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1823
unsigned long long flags
Definition: pe_types.h:332
const char * uname
Definition: pe_types.h:196
GSList * keys
Definition: internal.h:78
char * uuid
Definition: pe_types.h:393
gboolean update_action_flags(pe_action_t *action, enum pe_action_flags flags, const char *source, int line)
GListPtr actions
Definition: pe_types.h:343
GListPtr active
Definition: internal.h:87
pe_action_t * post_done
Definition: internal.h:85
struct notify_entry_s notify_entry_t
gboolean expand_notification_data(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
GListPtr children
Definition: pe_types.h:361
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:573
GListPtr demote
Definition: internal.h:91
#define crm_err(fmt, args...)
Definition: logging.h:363
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_PROMOTE
Definition: crm.h:202
GListPtr inactive
Definition: internal.h:88
#define add_notify_env(n_data, key, value)
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:258
#define pe_flag_stdout
Definition: pe_types.h:115
enum pe_action_flags flags
Definition: pe_types.h:397
GListPtr promote
Definition: internal.h:92
#define RSC_CANCEL
Definition: crm.h:191
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:19
pe_action_t * find_first_action(GListPtr input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1442
unsigned long long flags
Definition: pe_types.h:135
#define safe_str_eq(a, b)
Definition: util.h:65
GListPtr start
Definition: internal.h:89
const char * action
Definition: internal.h:80
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition: utils.c:215
gboolean unclean
Definition: pe_types.h:204
GList * GListPtr
Definition: crm.h:214
#define crm_info(fmt, args...)
Definition: logging.h:366
pe_action_t * pre_done
Definition: internal.h:84
gboolean online
Definition: pe_types.h:200
action_tasks
Definition: common.h:47
pe_action_t * pre
Definition: internal.h:82
#define RSC_DEMOTE
Definition: crm.h:204
void create_secondary_notification(pe_action_t *action, pe_resource_t *rsc, pe_action_t *stonith_op, pe_working_set_t *data_set)
char * id
Definition: pe_types.h:305
GHashTable * allowed_nodes
Definition: pe_types.h:352
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, pe_node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Definition: utils.c:485