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