pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
pe_notif.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2022 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 
32 static gint
33 compare_notify_entries(gconstpointer a, gconstpointer b)
34 {
35  int tmp;
36  const notify_entry_t *entry_a = a;
37  const notify_entry_t *entry_b = b;
38 
39  // NULL a or b is not actually possible
40  if ((entry_a == NULL) && (entry_b == NULL)) {
41  return 0;
42  }
43  if (entry_a == NULL) {
44  return 1;
45  }
46  if (entry_b == NULL) {
47  return -1;
48  }
49 
50  // NULL resources sort first
51  if ((entry_a->rsc == NULL) && (entry_b->rsc == NULL)) {
52  return 0;
53  }
54  if (entry_a->rsc == NULL) {
55  return 1;
56  }
57  if (entry_b->rsc == NULL) {
58  return -1;
59  }
60 
61  // Compare resource names
62  tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
63  if (tmp != 0) {
64  return tmp;
65  }
66 
67  // Otherwise NULL nodes sort first
68  if ((entry_a->node == NULL) && (entry_b->node == NULL)) {
69  return 0;
70  }
71  if (entry_a->node == NULL) {
72  return 1;
73  }
74  if (entry_b->node == NULL) {
75  return -1;
76  }
77 
78  // Finally, compare node names
79  return strcmp(entry_a->node->details->id, entry_b->node->details->id);
80 }
81 
91 static notify_entry_t *
92 dup_notify_entry(notify_entry_t *entry)
93 {
94  notify_entry_t *dup = calloc(1, sizeof(notify_entry_t));
95 
96  CRM_ASSERT(dup != NULL);
97  dup->rsc = entry->rsc;
98  dup->node = entry->node;
99  return dup;
100 }
101 
115 static void
116 get_node_names(GList *list, GString **all_node_names, GString **host_node_names)
117 {
118  if (all_node_names != NULL) {
119  *all_node_names = NULL;
120  }
121  if (host_node_names != NULL) {
122  *host_node_names = NULL;
123  }
124 
125  for (GList *iter = list; iter != NULL; iter = iter->next) {
126  pe_node_t *node = (pe_node_t *) iter->data;
127 
128  if (node->details->uname == NULL) {
129  continue;
130  }
131 
132  // Always add to list of all node names
133  if (all_node_names != NULL) {
134  pcmk__add_word(all_node_names, 1024, node->details->uname);
135  }
136 
137  // Add to host node name list if appropriate
138  if (host_node_names != NULL) {
139  if (pe__is_guest_node(node)
140  && (node->details->remote_rsc->container->running_on != NULL)) {
141  node = pe__current_node(node->details->remote_rsc->container);
142  if (node->details->uname == NULL) {
143  continue;
144  }
145  }
146  pcmk__add_word(host_node_names, 1024, node->details->uname);
147  }
148  }
149 
150  if ((all_node_names != NULL) && (*all_node_names == NULL)) {
151  *all_node_names = g_string_new(" ");
152  }
153  if ((host_node_names != NULL) && (*host_node_names == NULL)) {
154  *host_node_names = g_string_new(" ");
155  }
156 }
157 
172 static GList *
173 notify_entries_to_strings(GList *list, GString **rsc_names,
174  GString **node_names)
175 {
176  const char *last_rsc_id = NULL;
177 
178  // Initialize output lists to NULL
179  if (rsc_names != NULL) {
180  *rsc_names = NULL;
181  }
182  if (node_names != NULL) {
183  *node_names = NULL;
184  }
185 
186  // Sort input list for user-friendliness (and ease of filtering duplicates)
187  list = g_list_sort(list, compare_notify_entries);
188 
189  for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
190  notify_entry_t *entry = (notify_entry_t *) gIter->data;
191 
192  // Entry must have a resource (with ID)
193  CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
194  && (entry->rsc->id != NULL));
195  if ((entry == NULL) || (entry->rsc == NULL)
196  || (entry->rsc->id == NULL)) {
197  continue;
198  }
199 
200  // Entry must have a node unless listing inactive resources
201  CRM_LOG_ASSERT((node_names == NULL) || (entry->node != NULL));
202  if ((node_names != NULL) && (entry->node == NULL)) {
203  continue;
204  }
205 
206  // Don't add duplicates of a particular clone instance
207  if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
208  continue;
209  }
210  last_rsc_id = entry->rsc->id;
211 
212  if (rsc_names != NULL) {
213  pcmk__add_word(rsc_names, 1024, entry->rsc->id);
214  }
215  if ((node_names != NULL) && (entry->node->details->uname != NULL)) {
216  pcmk__add_word(node_names, 1024, entry->node->details->uname);
217  }
218  }
219 
220  // If there are no entries, return "empty" lists
221  if ((rsc_names != NULL) && (*rsc_names == NULL)) {
222  *rsc_names = g_string_new(" ");
223  }
224  if ((node_names != NULL) && (*node_names == NULL)) {
225  *node_names = g_string_new(" ");
226  }
227 
228  return list;
229 }
230 
239 static void
240 copy_meta_to_notify(gpointer key, gpointer value, gpointer user_data)
241 {
242  pe_action_t *notify = (pe_action_t *) user_data;
243 
244  /* Any existing meta-attributes (for example, the action timeout) are for
245  * the notify action itself, so don't override those.
246  */
247  if (g_hash_table_lookup(notify->meta, (const char *) key) != NULL) {
248  return;
249  }
250 
251  g_hash_table_insert(notify->meta, strdup((const char *) key),
252  strdup((const char *) value));
253 }
254 
255 static void
256 add_notify_data_to_action_meta(notify_data_t *n_data, pe_action_t *action)
257 {
258  for (GSList *item = n_data->keys; item; item = item->next) {
259  pcmk_nvpair_t *nvpair = item->data;
260 
261  add_hash_param(action->meta, nvpair->name, nvpair->value);
262  }
263 }
264 
276 static pe_action_t *
277 new_notify_pseudo_action(pe_resource_t *rsc, const pe_action_t *action,
278  const char *notif_action, const char *notif_type)
279 {
280  pe_action_t *notify = NULL;
281 
282  notify = custom_action(rsc,
283  pcmk__notify_key(rsc->id, notif_type, action->task),
284  notif_action, NULL,
286  TRUE, rsc->cluster);
288  add_hash_param(notify->meta, "notify_key_type", notif_type);
289  add_hash_param(notify->meta, "notify_key_operation", action->task);
290  return notify;
291 }
292 
305 static pe_action_t *
306 new_notify_action(pe_resource_t *rsc, pe_node_t *node, pe_action_t *op,
307  pe_action_t *notify_done, notify_data_t *n_data)
308 {
309  char *key = NULL;
310  pe_action_t *notify_action = NULL;
311  const char *value = NULL;
312  const char *task = NULL;
313  const char *skip_reason = NULL;
314 
315  CRM_CHECK((rsc != NULL) && (node != NULL), return NULL);
316 
317  // Ensure we have all the info we need
318  if (op == NULL) {
319  skip_reason = "no action";
320  } else if (notify_done == NULL) {
321  skip_reason = "no parent notification";
322  } else if (!node->details->online) {
323  skip_reason = "node offline";
324  } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
325  skip_reason = "original action not runnable";
326  }
327  if (skip_reason != NULL) {
328  pe_rsc_trace(rsc, "Skipping notify action for %s on %s: %s",
329  rsc->id, pe__node_name(node), skip_reason);
330  return NULL;
331  }
332 
333  value = g_hash_table_lookup(op->meta, "notify_type"); // "pre" or "post"
334  task = g_hash_table_lookup(op->meta, "notify_operation"); // original action
335 
336  pe_rsc_trace(rsc, "Creating notify action for %s on %s (%s-%s)",
337  rsc->id, pe__node_name(node), value, task);
338 
339  // Create the notify action
340  key = pcmk__notify_key(rsc->id, value, task);
341  notify_action = custom_action(rsc, key, op->task, node,
343  TRUE, rsc->cluster);
344 
345  // Add meta-data to notify action
346  g_hash_table_foreach(op->meta, copy_meta_to_notify, notify_action);
347  add_notify_data_to_action_meta(n_data, notify_action);
348 
349  // Order notify after original action and before parent notification
350  order_actions(op, notify_action, pe_order_optional);
351  order_actions(notify_action, notify_done, pe_order_optional);
352  return notify_action;
353 }
354 
363 static void
364 new_post_notify_action(pe_resource_t *rsc, pe_node_t *node,
365  notify_data_t *n_data)
366 {
367  pe_action_t *notify = NULL;
368 
369  CRM_ASSERT(n_data != NULL);
370 
371  // Create the "post-" notify action for specified instance
372  notify = new_notify_action(rsc, node, n_data->post, n_data->post_done,
373  n_data);
374  if (notify != NULL) {
375  notify->priority = INFINITY;
376  }
377 
378  // Order recurring monitors after all "post-" notifications complete
379  if (n_data->post_done == NULL) {
380  return;
381  }
382  for (GList *iter = rsc->actions; iter != NULL; iter = iter->next) {
383  pe_action_t *mon = (pe_action_t *) iter->data;
384  const char *interval_ms_s = NULL;
385 
386  interval_ms_s = g_hash_table_lookup(mon->meta,
388  if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)
389  || pcmk__str_eq(mon->task, RSC_CANCEL, pcmk__str_none)) {
390  continue; // Not a recurring monitor
391  }
393  }
394 }
395 
429  pe_action_t *action, pe_action_t *complete)
430 {
431  notify_data_t *n_data = NULL;
432 
433  if (!pcmk_is_set(rsc->flags, pe_rsc_notify)) {
434  return NULL;
435  }
436 
437  n_data = calloc(1, sizeof(notify_data_t));
438  CRM_ASSERT(n_data != NULL);
439 
440  n_data->action = task;
441 
442  if (action != NULL) { // Need "pre-" pseudo-actions
443 
444  // Create "pre-" notify pseudo-action for clone
445  n_data->pre = new_notify_pseudo_action(rsc, action, RSC_NOTIFY, "pre");
447  add_hash_param(n_data->pre->meta, "notify_type", "pre");
448  add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
449 
450  // Create "pre-" notifications complete pseudo-action for clone
451  n_data->pre_done = new_notify_pseudo_action(rsc, action, RSC_NOTIFIED,
452  "confirmed-pre");
454  add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
455  add_hash_param(n_data->pre_done->meta,
456  "notify_operation", n_data->action);
457 
458  // Order "pre-" -> "pre-" complete -> original action
459  order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
461  }
462 
463  if (complete != NULL) { // Need "post-" pseudo-actions
464 
465  // Create "post-" notify pseudo-action for clone
466  n_data->post = new_notify_pseudo_action(rsc, complete, RSC_NOTIFY,
467  "post");
468  n_data->post->priority = INFINITY;
469  if (pcmk_is_set(complete->flags, pe_action_runnable)) {
471  } else {
473  }
474  add_hash_param(n_data->post->meta, "notify_type", "post");
475  add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
476 
477  // Create "post-" notifications complete pseudo-action for clone
478  n_data->post_done = new_notify_pseudo_action(rsc, complete,
479  RSC_NOTIFIED,
480  "confirmed-post");
481  n_data->post_done->priority = INFINITY;
482  if (pcmk_is_set(complete->flags, pe_action_runnable)) {
484  } else {
486  }
487  add_hash_param(n_data->post_done->meta, "notify_type", "post");
488  add_hash_param(n_data->post_done->meta,
489  "notify_operation", n_data->action);
490 
491  // Order original action complete -> "post-" -> "post-" complete
492  order_actions(complete, n_data->post, pe_order_implies_then);
494  }
495 
496  // If we created both, order "pre-" complete -> "post-"
497  if ((action != NULL) && (complete != NULL)) {
498  order_actions(n_data->pre_done, n_data->post, pe_order_optional);
499  }
500  return n_data;
501 }
502 
513 static notify_entry_t *
514 new_notify_entry(pe_resource_t *rsc, pe_node_t *node)
515 {
516  notify_entry_t *entry = calloc(1, sizeof(notify_entry_t));
517 
518  CRM_ASSERT(entry != NULL);
519  entry->rsc = rsc;
520  entry->node = node;
521  return entry;
522 }
523 
532 static void
533 collect_resource_data(pe_resource_t *rsc, bool activity, notify_data_t *n_data)
534 {
535  GList *iter = NULL;
536  notify_entry_t *entry = NULL;
537  pe_node_t *node = NULL;
538 
539  if (n_data == NULL) {
540  return;
541  }
542 
543  if (n_data->allowed_nodes == NULL) {
544  n_data->allowed_nodes = rsc->allowed_nodes;
545  }
546 
547  // If this is a clone, call recursively for each instance
548  if (rsc->children != NULL) {
549  for (iter = rsc->children; iter != NULL; iter = iter->next) {
550  pe_resource_t *child = (pe_resource_t *) iter->data;
551 
552  collect_resource_data(child, activity, n_data);
553  }
554  return;
555  }
556 
557  // This is a notification for a single clone instance
558 
559  if (rsc->running_on != NULL) {
560  node = rsc->running_on->data; // First is sufficient
561  }
562  entry = new_notify_entry(rsc, node);
563 
564  // Add notification indicating the resource state
565  switch (rsc->role) {
566  case RSC_ROLE_STOPPED:
567  n_data->inactive = g_list_prepend(n_data->inactive, entry);
568  break;
569 
570  case RSC_ROLE_STARTED:
571  n_data->active = g_list_prepend(n_data->active, entry);
572  break;
573 
574  case RSC_ROLE_UNPROMOTED:
575  n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
576  n_data->active = g_list_prepend(n_data->active,
577  dup_notify_entry(entry));
578  break;
579 
580  case RSC_ROLE_PROMOTED:
581  n_data->promoted = g_list_prepend(n_data->promoted, entry);
582  n_data->active = g_list_prepend(n_data->active,
583  dup_notify_entry(entry));
584  break;
585 
586  default:
587  crm_err("Resource %s role on %s (%s) is not supported for "
588  "notifications (bug?)",
589  rsc->id, pe__node_name(node), role2text(rsc->role));
590  free(entry);
591  break;
592  }
593 
594  if (!activity) {
595  return;
596  }
597 
598  // Add notification entries for each of the resource's actions
599  for (iter = rsc->actions; iter != NULL; iter = iter->next) {
600  pe_action_t *op = (pe_action_t *) iter->data;
601 
602  if (!pcmk_is_set(op->flags, pe_action_optional) && (op->node != NULL)) {
603  enum action_tasks task = text2task(op->task);
604 
605  if ((task == stop_rsc) && op->node->details->unclean) {
606  // Create anyway (additional noise if node can't be fenced)
607  } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
608  continue;
609  }
610 
611  entry = new_notify_entry(rsc, op->node);
612 
613  switch (task) {
614  case start_rsc:
615  n_data->start = g_list_prepend(n_data->start, entry);
616  break;
617  case stop_rsc:
618  n_data->stop = g_list_prepend(n_data->stop, entry);
619  break;
620  case action_promote:
621  n_data->promote = g_list_prepend(n_data->promote, entry);
622  break;
623  case action_demote:
624  n_data->demote = g_list_prepend(n_data->demote, entry);
625  break;
626  default:
627  free(entry);
628  break;
629  }
630  }
631  }
632 }
633 
634 // For (char *) value
635 #define add_notify_env(n_data, key, value) do { \
636  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
637  } while (0)
638 
639 // For (GString *) value
640 #define add_notify_env_gs(n_data, key, value) do { \
641  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
642  (const char *) value->str); \
643  } while (0)
644 
645 // For (GString *) value
646 #define add_notify_env_free_gs(n_data, key, value) do { \
647  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
648  (const char *) value->str); \
649  g_string_free(value, TRUE); value = NULL; \
650  } while (0)
651 
659 static void
660 add_notif_keys(pe_resource_t *rsc, notify_data_t *n_data)
661 {
662  bool required = false; // Whether to make notify actions required
663  GString *rsc_list = NULL;
664  GString *node_list = NULL;
665  GString *metal_list = NULL;
666  const char *source = NULL;
667  GList *nodes = NULL;
668 
669  n_data->stop = notify_entries_to_strings(n_data->stop,
670  &rsc_list, &node_list);
671  if ((strcmp(" ", (const char *) rsc_list->str) != 0)
672  && pcmk__str_eq(n_data->action, RSC_STOP, pcmk__str_none)) {
673  required = true;
674  }
675  add_notify_env_free_gs(n_data, "notify_stop_resource", rsc_list);
676  add_notify_env_free_gs(n_data, "notify_stop_uname", node_list);
677 
678  if ((n_data->start != NULL)
679  && pcmk__str_eq(n_data->action, RSC_START, pcmk__str_none)) {
680  required = true;
681  }
682  n_data->start = notify_entries_to_strings(n_data->start,
683  &rsc_list, &node_list);
684  add_notify_env_free_gs(n_data, "notify_start_resource", rsc_list);
685  add_notify_env_free_gs(n_data, "notify_start_uname", node_list);
686 
687  if ((n_data->demote != NULL)
688  && pcmk__str_eq(n_data->action, RSC_DEMOTE, pcmk__str_none)) {
689  required = true;
690  }
691  n_data->demote = notify_entries_to_strings(n_data->demote,
692  &rsc_list, &node_list);
693  add_notify_env_free_gs(n_data, "notify_demote_resource", rsc_list);
694  add_notify_env_free_gs(n_data, "notify_demote_uname", node_list);
695 
696  if ((n_data->promote != NULL)
697  && pcmk__str_eq(n_data->action, RSC_PROMOTE, pcmk__str_none)) {
698  required = true;
699  }
700  n_data->promote = notify_entries_to_strings(n_data->promote,
701  &rsc_list, &node_list);
702  add_notify_env_free_gs(n_data, "notify_promote_resource", rsc_list);
703  add_notify_env_free_gs(n_data, "notify_promote_uname", node_list);
704 
705  n_data->active = notify_entries_to_strings(n_data->active,
706  &rsc_list, &node_list);
707  add_notify_env_free_gs(n_data, "notify_active_resource", rsc_list);
708  add_notify_env_free_gs(n_data, "notify_active_uname", node_list);
709 
710  n_data->unpromoted = notify_entries_to_strings(n_data->unpromoted,
711  &rsc_list, &node_list);
712  add_notify_env_gs(n_data, "notify_unpromoted_resource", rsc_list);
713  add_notify_env_gs(n_data, "notify_unpromoted_uname", node_list);
714 
715  // Deprecated: kept for backward compatibility with older resource agents
716  add_notify_env_free_gs(n_data, "notify_slave_resource", rsc_list);
717  add_notify_env_free_gs(n_data, "notify_slave_uname", node_list);
718 
719  n_data->promoted = notify_entries_to_strings(n_data->promoted,
720  &rsc_list, &node_list);
721  add_notify_env_gs(n_data, "notify_promoted_resource", rsc_list);
722  add_notify_env_gs(n_data, "notify_promoted_uname", node_list);
723 
724  // Deprecated: kept for backward compatibility with older resource agents
725  add_notify_env_free_gs(n_data, "notify_master_resource", rsc_list);
726  add_notify_env_free_gs(n_data, "notify_master_uname", node_list);
727 
728  n_data->inactive = notify_entries_to_strings(n_data->inactive,
729  &rsc_list, NULL);
730  add_notify_env_free_gs(n_data, "notify_inactive_resource", rsc_list);
731 
732  nodes = g_hash_table_get_values(n_data->allowed_nodes);
733  if (!pcmk__is_daemon) {
734  /* For display purposes, sort the node list, for consistent
735  * regression test output (while avoiding the performance hit
736  * for the live cluster).
737  */
738  nodes = g_list_sort(nodes, pe__cmp_node_name);
739  }
740  get_node_names(nodes, &node_list, NULL);
741  add_notify_env_free_gs(n_data, "notify_available_uname", node_list);
742  g_list_free(nodes);
743 
744  source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
745  if (pcmk__str_eq("host", source, pcmk__str_none)) {
746  get_node_names(rsc->cluster->nodes, &node_list, &metal_list);
747  add_notify_env_free_gs(n_data, "notify_all_hosts", metal_list);
748  } else {
749  get_node_names(rsc->cluster->nodes, &node_list, NULL);
750  }
751  add_notify_env_free_gs(n_data, "notify_all_uname", node_list);
752 
753  if (required && (n_data->pre != NULL)) {
756  }
757 
758  if (required && (n_data->post != NULL)) {
761  }
762 }
763 
764 /*
765  * \internal
766  * \brief Find any remote connection start relevant to an action
767  *
768  * \param[in] action Action to check
769  *
770  * \return If action is behind a remote connection, connection's start
771  */
772 static pe_action_t *
773 find_remote_start(pe_action_t *action)
774 {
775  if ((action != NULL) && (action->node != NULL)) {
776  pe_resource_t *remote_rsc = action->node->details->remote_rsc;
777 
778  if (remote_rsc != NULL) {
779  return find_first_action(remote_rsc->actions, NULL, RSC_START,
780  NULL);
781  }
782  }
783  return NULL;
784 }
785 
793 static void
794 create_notify_actions(pe_resource_t *rsc, notify_data_t *n_data)
795 {
796  GList *iter = NULL;
797  pe_action_t *stop = NULL;
798  pe_action_t *start = NULL;
799  enum action_tasks task = text2task(n_data->action);
800 
801  // If this is a clone, call recursively for each instance
802  if (rsc->children != NULL) {
803  g_list_foreach(rsc->children, (GFunc) create_notify_actions, n_data);
804  return;
805  }
806 
807  // Add notification meta-attributes to original actions
808  for (iter = rsc->actions; iter != NULL; iter = iter->next) {
809  pe_action_t *op = (pe_action_t *) iter->data;
810 
811  if (!pcmk_is_set(op->flags, pe_action_optional) && (op->node != NULL)) {
812  switch (text2task(op->task)) {
813  case start_rsc:
814  case stop_rsc:
815  case action_promote:
816  case action_demote:
817  add_notify_data_to_action_meta(n_data, op);
818  break;
819  default:
820  break;
821  }
822  }
823  }
824 
825  // Skip notify action itself if original action was not needed
826  switch (task) {
827  case start_rsc:
828  if (n_data->start == NULL) {
829  pe_rsc_trace(rsc, "No notify action needed for %s %s",
830  rsc->id, n_data->action);
831  return;
832  }
833  break;
834 
835  case action_promote:
836  if (n_data->promote == NULL) {
837  pe_rsc_trace(rsc, "No notify action needed for %s %s",
838  rsc->id, n_data->action);
839  return;
840  }
841  break;
842 
843  case action_demote:
844  if (n_data->demote == NULL) {
845  pe_rsc_trace(rsc, "No notify action needed for %s %s",
846  rsc->id, n_data->action);
847  return;
848  }
849  break;
850 
851  default:
852  // We cannot do same for stop because it might be implied by fencing
853  break;
854  }
855 
856  pe_rsc_trace(rsc, "Creating notify actions for %s %s",
857  rsc->id, n_data->action);
858 
859  // Create notify actions for stop or demote
860  if ((rsc->role != RSC_ROLE_STOPPED)
861  && ((task == stop_rsc) || (task == action_demote))) {
862 
863  stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
864 
865  for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
866  pe_node_t *current_node = (pe_node_t *) iter->data;
867 
868  /* If a stop is a pseudo-action implied by fencing, don't try to
869  * notify the node getting fenced.
870  */
871  if ((stop != NULL) && pcmk_is_set(stop->flags, pe_action_pseudo)
872  && (current_node->details->unclean
873  || current_node->details->remote_requires_reset)) {
874  continue;
875  }
876 
877  new_notify_action(rsc, current_node, n_data->pre,
878  n_data->pre_done, n_data);
879 
880  if ((task == action_demote) || (stop == NULL)
881  || pcmk_is_set(stop->flags, pe_action_optional)) {
882  new_post_notify_action(rsc, current_node, n_data);
883  }
884  }
885  }
886 
887  // Create notify actions for start or promote
888  if ((rsc->next_role != RSC_ROLE_STOPPED)
889  && ((task == start_rsc) || (task == action_promote))) {
890 
891  start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
892  if (start != NULL) {
893  pe_action_t *remote_start = find_remote_start(start);
894 
895  if ((remote_start != NULL)
896  && !pcmk_is_set(remote_start->flags, pe_action_runnable)) {
897  /* Start and promote actions for a clone instance behind
898  * a Pacemaker Remote connection happen after the
899  * connection starts. If the connection start is blocked, do
900  * not schedule notifications for these actions.
901  */
902  return;
903  }
904  }
905  if (rsc->allocated_to == NULL) {
906  pe_proc_err("Next role '%s' but %s is not allocated",
907  role2text(rsc->next_role), rsc->id);
908  return;
909  }
910  if ((task != start_rsc) || (start == NULL)
911  || pcmk_is_set(start->flags, pe_action_optional)) {
912 
913  new_notify_action(rsc, rsc->allocated_to, n_data->pre,
914  n_data->pre_done, n_data);
915  }
916  new_post_notify_action(rsc, rsc->allocated_to, n_data);
917  }
918 }
919 
927 void
929 {
930  if ((rsc == NULL) || (n_data == NULL)) {
931  return;
932  }
933  collect_resource_data(rsc, true, n_data);
934  add_notif_keys(rsc, n_data);
935  create_notify_actions(rsc, n_data);
936 }
937 
944 void
946 {
947  if (n_data == NULL) {
948  return;
949  }
950  g_list_free_full(n_data->stop, free);
951  g_list_free_full(n_data->start, free);
952  g_list_free_full(n_data->demote, free);
953  g_list_free_full(n_data->promote, free);
954  g_list_free_full(n_data->promoted, free);
955  g_list_free_full(n_data->unpromoted, free);
956  g_list_free_full(n_data->active, free);
957  g_list_free_full(n_data->inactive, free);
958  pcmk_free_nvpairs(n_data->keys);
959  free(n_data);
960 }
961 
976 void
978  pe_action_t *stonith_op)
979 {
980  notify_data_t *n_data;
981 
982  crm_info("Ordering notifications for implied %s after fencing", stop->uuid);
983  n_data = pe__clone_notif_pseudo_ops(rsc, RSC_STOP, NULL, stonith_op);
984 
985  if (n_data != NULL) {
986  collect_resource_data(rsc, false, n_data);
987  add_notify_env(n_data, "notify_stop_resource", rsc->id);
988  add_notify_env(n_data, "notify_stop_uname", stop->node->details->uname);
989  create_notify_actions(uber_parent(rsc), n_data);
991  }
992 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define RSC_STOP
Definition: crm.h:202
char * name
Definition: nvpair.h:30
#define INFINITY
Definition: crm.h:99
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:102
GHashTable * allowed_nodes
Definition: internal.h:227
int priority
Definition: pe_types.h:404
pe_resource_t * container
Definition: pe_types.h:387
char * value
Definition: nvpair.h:31
GList * start
Definition: internal.h:221
enum rsc_role_e role
Definition: pe_types.h:377
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:180
#define RSC_NOTIFIED
Definition: crm.h:211
GList * children
Definition: pe_types.h:384
#define add_notify_env_free_gs(n_data, key, value)
Definition: pe_notif.c:646
enum rsc_role_e next_role
Definition: pe_types.h:378
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1296
pe_resource_t * remote_rsc
Definition: pe_types.h:237
GHashTable * meta
Definition: pe_types.h:380
#define pe_rsc_notify
Definition: pe_types.h:261
void pe__order_notifs_after_fencing(pe_action_t *stop, pe_resource_t *rsc, pe_action_t *stonith_op)
Definition: pe_notif.c:977
enum action_tasks text2task(const char *task)
Definition: common.c:353
void pe__create_notifications(pe_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:928
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:211
#define add_notify_env_gs(n_data, key, value)
Definition: pe_notif.c:640
#define RSC_START
Definition: crm.h:199
pe_node_t * allocated_to
Definition: pe_types.h:370
GList * inactive
Definition: internal.h:220
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:224
#define pe_proc_err(fmt...)
Definition: internal.h:59
gboolean remote_requires_reset
Definition: pe_types.h:231
#define RSC_NOTIFY
Definition: crm.h:210
const char * action
Definition: pcmk_fence.c:30
GList * nodes
Definition: pe_types.h:164
const char * role2text(enum rsc_role_e role)
Definition: common.c:454
GList * active
Definition: internal.h:219
GList * stop
Definition: internal.h:222
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:229
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:912
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
pe_action_t * post
Definition: internal.h:215
char * task
Definition: pe_types.h:410
void pe__free_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:945
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
GList * promote
Definition: internal.h:224
GHashTable * meta
Definition: pe_types.h:420
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
struct pe_node_shared_s * details
Definition: pe_types.h:252
notify_data_t * pe__clone_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
Definition: pe_notif.c:428
pe_node_t * node
Definition: pe_types.h:407
bool pcmk__is_daemon
Definition: logging.c:47
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:474
unsigned long long flags
Definition: pe_types.h:355
const char * uname
Definition: pe_types.h:216
GList * actions
Definition: pe_types.h:366
GSList * keys
Definition: internal.h:210
char * uuid
Definition: pe_types.h:411
GList * promoted
Definition: internal.h:225
pe_action_t * post_done
Definition: internal.h:217
GList * unpromoted
Definition: internal.h:226
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:504
#define crm_err(fmt, args...)
Definition: logging.h:359
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_PROMOTE
Definition: crm.h:205
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:298
GList * demote
Definition: internal.h:223
GList * running_on
Definition: pe_types.h:373
enum pe_action_flags flags
Definition: pe_types.h:415
pe_working_set_t * cluster
Definition: pe_types.h:335
struct notify_entry_s notify_entry_t
#define RSC_CANCEL
Definition: crm.h:194
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
const char * action
Definition: internal.h:212
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, const pe_node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Create or update an action object.
Definition: pe_actions.c:940
gboolean unclean
Definition: pe_types.h:224
#define crm_info(fmt, args...)
Definition: logging.h:362
#define add_notify_env(n_data, key, value)
Definition: pe_notif.c:635
pe_action_t * pre_done
Definition: internal.h:216
gboolean online
Definition: pe_types.h:220
action_tasks
Definition: common.h:61
pe_action_t * pre
Definition: internal.h:214
#define RSC_DEMOTE
Definition: crm.h:207
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375