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