pacemaker  2.1.7-0f7f88312f
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 
13 #include <crm/pengine/internal.h>
14 #include <pacemaker-internal.h>
15 
16 #include "pe_status_private.h"
17 
18 typedef struct notify_entry_s {
19  const pcmk_resource_t *rsc;
20  const pcmk_node_t *node;
22 
36 static gint
37 compare_notify_entries(gconstpointer a, gconstpointer b)
38 {
39  int tmp;
40  const notify_entry_t *entry_a = a;
41  const notify_entry_t *entry_b = b;
42 
43  // NULL a or b is not actually possible
44  if ((entry_a == NULL) && (entry_b == NULL)) {
45  return 0;
46  }
47  if (entry_a == NULL) {
48  return 1;
49  }
50  if (entry_b == NULL) {
51  return -1;
52  }
53 
54  // NULL resources sort first
55  if ((entry_a->rsc == NULL) && (entry_b->rsc == NULL)) {
56  return 0;
57  }
58  if (entry_a->rsc == NULL) {
59  return 1;
60  }
61  if (entry_b->rsc == NULL) {
62  return -1;
63  }
64 
65  // Compare resource names
66  tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
67  if (tmp != 0) {
68  return tmp;
69  }
70 
71  // Otherwise NULL nodes sort first
72  if ((entry_a->node == NULL) && (entry_b->node == NULL)) {
73  return 0;
74  }
75  if (entry_a->node == NULL) {
76  return 1;
77  }
78  if (entry_b->node == NULL) {
79  return -1;
80  }
81 
82  // Finally, compare node names
83  return strcmp(entry_a->node->details->id, entry_b->node->details->id);
84 }
85 
95 static notify_entry_t *
96 dup_notify_entry(const notify_entry_t *entry)
97 {
98  notify_entry_t *dup = calloc(1, sizeof(notify_entry_t));
99 
100  CRM_ASSERT(dup != NULL);
101  dup->rsc = entry->rsc;
102  dup->node = entry->node;
103  return dup;
104 }
105 
119 static void
120 get_node_names(const GList *list, GString **all_node_names,
121  GString **host_node_names)
122 {
123  if (all_node_names != NULL) {
124  *all_node_names = NULL;
125  }
126  if (host_node_names != NULL) {
127  *host_node_names = NULL;
128  }
129 
130  for (const GList *iter = list; iter != NULL; iter = iter->next) {
131  const pcmk_node_t *node = (const pcmk_node_t *) iter->data;
132 
133  if (node->details->uname == NULL) {
134  continue;
135  }
136 
137  // Always add to list of all node names
138  if (all_node_names != NULL) {
139  pcmk__add_word(all_node_names, 1024, node->details->uname);
140  }
141 
142  // Add to host node name list if appropriate
143  if (host_node_names != NULL) {
144  if (pe__is_guest_node(node)
145  && (node->details->remote_rsc->container->running_on != NULL)) {
146  node = pe__current_node(node->details->remote_rsc->container);
147  if (node->details->uname == NULL) {
148  continue;
149  }
150  }
151  pcmk__add_word(host_node_names, 1024, node->details->uname);
152  }
153  }
154 
155  if ((all_node_names != NULL) && (*all_node_names == NULL)) {
156  *all_node_names = g_string_new(" ");
157  }
158  if ((host_node_names != NULL) && (*host_node_names == NULL)) {
159  *host_node_names = g_string_new(" ");
160  }
161 }
162 
177 static GList *
178 notify_entries_to_strings(GList *list, GString **rsc_names,
179  GString **node_names)
180 {
181  const char *last_rsc_id = NULL;
182 
183  // Initialize output lists to NULL
184  if (rsc_names != NULL) {
185  *rsc_names = NULL;
186  }
187  if (node_names != NULL) {
188  *node_names = NULL;
189  }
190 
191  // Sort input list for user-friendliness (and ease of filtering duplicates)
192  list = g_list_sort(list, compare_notify_entries);
193 
194  for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
195  notify_entry_t *entry = (notify_entry_t *) gIter->data;
196 
197  // Entry must have a resource (with ID)
198  CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
199  && (entry->rsc->id != NULL));
200  if ((entry == NULL) || (entry->rsc == NULL)
201  || (entry->rsc->id == NULL)) {
202  continue;
203  }
204 
205  // Entry must have a node unless listing inactive resources
206  CRM_LOG_ASSERT((node_names == NULL) || (entry->node != NULL));
207  if ((node_names != NULL) && (entry->node == NULL)) {
208  continue;
209  }
210 
211  // Don't add duplicates of a particular clone instance
212  if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
213  continue;
214  }
215  last_rsc_id = entry->rsc->id;
216 
217  if (rsc_names != NULL) {
218  pcmk__add_word(rsc_names, 1024, entry->rsc->id);
219  }
220  if ((node_names != NULL) && (entry->node->details->uname != NULL)) {
221  pcmk__add_word(node_names, 1024, entry->node->details->uname);
222  }
223  }
224 
225  // If there are no entries, return "empty" lists
226  if ((rsc_names != NULL) && (*rsc_names == NULL)) {
227  *rsc_names = g_string_new(" ");
228  }
229  if ((node_names != NULL) && (*node_names == NULL)) {
230  *node_names = g_string_new(" ");
231  }
232 
233  return list;
234 }
235 
244 static void
245 copy_meta_to_notify(gpointer key, gpointer value, gpointer user_data)
246 {
247  pcmk_action_t *notify = (pcmk_action_t *) user_data;
248 
249  /* Any existing meta-attributes (for example, the action timeout) are for
250  * the notify action itself, so don't override those.
251  */
252  if (g_hash_table_lookup(notify->meta, (const char *) key) != NULL) {
253  return;
254  }
255 
256  g_hash_table_insert(notify->meta, strdup((const char *) key),
257  strdup((const char *) value));
258 }
259 
260 static void
261 add_notify_data_to_action_meta(const notify_data_t *n_data,
263 {
264  for (const GSList *item = n_data->keys; item; item = item->next) {
265  const pcmk_nvpair_t *nvpair = (const pcmk_nvpair_t *) item->data;
266 
267  add_hash_param(action->meta, nvpair->name, nvpair->value);
268  }
269 }
270 
282 static pcmk_action_t *
283 new_notify_pseudo_action(pcmk_resource_t *rsc, const pcmk_action_t *action,
284  const char *notif_action, const char *notif_type)
285 {
286  pcmk_action_t *notify = NULL;
287 
288  notify = custom_action(rsc,
289  pcmk__notify_key(rsc->id, notif_type, action->task),
290  notif_action, NULL,
292  rsc->cluster);
294  add_hash_param(notify->meta, "notify_key_type", notif_type);
295  add_hash_param(notify->meta, "notify_key_operation", action->task);
296  return notify;
297 }
298 
311 static pcmk_action_t *
312 new_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
313  pcmk_action_t *op, pcmk_action_t *notify_done,
314  const notify_data_t *n_data)
315 {
316  char *key = NULL;
317  pcmk_action_t *notify_action = NULL;
318  const char *value = NULL;
319  const char *task = NULL;
320  const char *skip_reason = NULL;
321 
322  CRM_CHECK((rsc != NULL) && (node != NULL), return NULL);
323 
324  // Ensure we have all the info we need
325  if (op == NULL) {
326  skip_reason = "no action";
327  } else if (notify_done == NULL) {
328  skip_reason = "no parent notification";
329  } else if (!node->details->online) {
330  skip_reason = "node offline";
331  } else if (!pcmk_is_set(op->flags, pcmk_action_runnable)) {
332  skip_reason = "original action not runnable";
333  }
334  if (skip_reason != NULL) {
335  pe_rsc_trace(rsc, "Skipping notify action for %s on %s: %s",
336  rsc->id, pe__node_name(node), skip_reason);
337  return NULL;
338  }
339 
340  value = g_hash_table_lookup(op->meta, "notify_type"); // "pre" or "post"
341  task = g_hash_table_lookup(op->meta, "notify_operation"); // original action
342 
343  pe_rsc_trace(rsc, "Creating notify action for %s on %s (%s-%s)",
344  rsc->id, pe__node_name(node), value, task);
345 
346  // Create the notify action
347  key = pcmk__notify_key(rsc->id, value, task);
348  notify_action = custom_action(rsc, key, op->task, node,
350  rsc->cluster);
351 
352  // Add meta-data to notify action
353  g_hash_table_foreach(op->meta, copy_meta_to_notify, notify_action);
354  add_notify_data_to_action_meta(n_data, notify_action);
355 
356  // Order notify after original action and before parent notification
357  order_actions(op, notify_action, pcmk__ar_ordered);
358  order_actions(notify_action, notify_done, pcmk__ar_ordered);
359  return notify_action;
360 }
361 
370 static void
371 new_post_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
372  notify_data_t *n_data)
373 {
374  pcmk_action_t *notify = NULL;
375 
376  CRM_ASSERT(n_data != 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  pcmk_action_t *mon = (pcmk_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, PCMK_ACTION_CANCEL, pcmk__str_none)) {
397  continue; // Not a recurring monitor
398  }
400  }
401 }
402 
436  pcmk_action_t *action, pcmk_action_t *complete)
437 {
438  notify_data_t *n_data = NULL;
439 
440  if (!pcmk_is_set(rsc->flags, pcmk_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, PCMK_ACTION_NOTIFY,
453  "pre");
455  add_hash_param(n_data->pre->meta, "notify_type", "pre");
456  add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
457 
458  // Create "pre-" notifications complete pseudo-action for clone
459  n_data->pre_done = new_notify_pseudo_action(rsc, action,
461  "confirmed-pre");
463  add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
464  add_hash_param(n_data->pre_done->meta,
465  "notify_operation", n_data->action);
466 
467  // Order "pre-" -> "pre-" complete -> original action
468  order_actions(n_data->pre, n_data->pre_done, pcmk__ar_ordered);
470  }
471 
472  if (complete != NULL) { // Need "post-" pseudo-actions
473 
474  // Create "post-" notify pseudo-action for clone
475  n_data->post = new_notify_pseudo_action(rsc, complete,
476  PCMK_ACTION_NOTIFY, "post");
477  n_data->post->priority = INFINITY;
478  if (pcmk_is_set(complete->flags, pcmk_action_runnable)) {
480  } else {
482  }
483  add_hash_param(n_data->post->meta, "notify_type", "post");
484  add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
485 
486  // Create "post-" notifications complete pseudo-action for clone
487  n_data->post_done = new_notify_pseudo_action(rsc, complete,
489  "confirmed-post");
490  n_data->post_done->priority = INFINITY;
491  if (pcmk_is_set(complete->flags, pcmk_action_runnable)) {
493  } else {
495  }
496  add_hash_param(n_data->post_done->meta, "notify_type", "post");
497  add_hash_param(n_data->post_done->meta,
498  "notify_operation", n_data->action);
499 
500  // Order original action complete -> "post-" -> "post-" complete
501  order_actions(complete, n_data->post, pcmk__ar_first_implies_then);
502  order_actions(n_data->post, n_data->post_done,
504  }
505 
506  // If we created both, order "pre-" complete -> "post-"
507  if ((action != NULL) && (complete != NULL)) {
508  order_actions(n_data->pre_done, n_data->post, pcmk__ar_ordered);
509  }
510  return n_data;
511 }
512 
523 static notify_entry_t *
524 new_notify_entry(const pcmk_resource_t *rsc, const pcmk_node_t *node)
525 {
526  notify_entry_t *entry = calloc(1, sizeof(notify_entry_t));
527 
528  CRM_ASSERT(entry != NULL);
529  entry->rsc = rsc;
530  entry->node = node;
531  return entry;
532 }
533 
542 static void
543 collect_resource_data(const pcmk_resource_t *rsc, bool activity,
544  notify_data_t *n_data)
545 {
546  const GList *iter = NULL;
547  notify_entry_t *entry = NULL;
548  const pcmk_node_t *node = NULL;
549 
550  if (n_data == NULL) {
551  return;
552  }
553 
554  if (n_data->allowed_nodes == NULL) {
555  n_data->allowed_nodes = rsc->allowed_nodes;
556  }
557 
558  // If this is a clone, call recursively for each instance
559  if (rsc->children != NULL) {
560  for (iter = rsc->children; iter != NULL; iter = iter->next) {
561  const pcmk_resource_t *child = (const pcmk_resource_t *) iter->data;
562 
563  collect_resource_data(child, activity, n_data);
564  }
565  return;
566  }
567 
568  // This is a notification for a single clone instance
569 
570  if (rsc->running_on != NULL) {
571  node = rsc->running_on->data; // First is sufficient
572  }
573  entry = new_notify_entry(rsc, node);
574 
575  // Add notification indicating the resource state
576  switch (rsc->role) {
577  case pcmk_role_stopped:
578  n_data->inactive = g_list_prepend(n_data->inactive, entry);
579  break;
580 
581  case pcmk_role_started:
582  n_data->active = g_list_prepend(n_data->active, entry);
583  break;
584 
586  n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
587  n_data->active = g_list_prepend(n_data->active,
588  dup_notify_entry(entry));
589  break;
590 
591  case pcmk_role_promoted:
592  n_data->promoted = g_list_prepend(n_data->promoted, entry);
593  n_data->active = g_list_prepend(n_data->active,
594  dup_notify_entry(entry));
595  break;
596 
597  default:
598  crm_err("Resource %s role on %s (%s) is not supported for "
599  "notifications (bug?)",
600  rsc->id, pe__node_name(node), role2text(rsc->role));
601  free(entry);
602  break;
603  }
604 
605  if (!activity) {
606  return;
607  }
608 
609  // Add notification entries for each of the resource's actions
610  for (iter = rsc->actions; iter != NULL; iter = iter->next) {
611  const pcmk_action_t *op = (const pcmk_action_t *) iter->data;
612 
614  && (op->node != NULL)) {
615  enum action_tasks task = text2task(op->task);
616 
617  if ((task == pcmk_action_stop) && op->node->details->unclean) {
618  // Create anyway (additional noise if node can't be fenced)
619  } else if (!pcmk_is_set(op->flags, pcmk_action_runnable)) {
620  continue;
621  }
622 
623  entry = new_notify_entry(rsc, op->node);
624 
625  switch (task) {
626  case pcmk_action_start:
627  n_data->start = g_list_prepend(n_data->start, entry);
628  break;
629  case pcmk_action_stop:
630  n_data->stop = g_list_prepend(n_data->stop, entry);
631  break;
632  case pcmk_action_promote:
633  n_data->promote = g_list_prepend(n_data->promote, entry);
634  break;
635  case pcmk_action_demote:
636  n_data->demote = g_list_prepend(n_data->demote, entry);
637  break;
638  default:
639  free(entry);
640  break;
641  }
642  }
643  }
644 }
645 
646 // For (char *) value
647 #define add_notify_env(n_data, key, value) do { \
648  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
649  } while (0)
650 
651 // For (GString *) value
652 #define add_notify_env_gs(n_data, key, value) do { \
653  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
654  (const char *) value->str); \
655  } while (0)
656 
657 // For (GString *) value
658 #define add_notify_env_free_gs(n_data, key, value) do { \
659  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
660  (const char *) value->str); \
661  g_string_free(value, TRUE); value = NULL; \
662  } while (0)
663 
671 static void
672 add_notif_keys(const pcmk_resource_t *rsc, notify_data_t *n_data)
673 {
674  bool required = false; // Whether to make notify actions required
675  GString *rsc_list = NULL;
676  GString *node_list = NULL;
677  GString *metal_list = NULL;
678  const char *source = NULL;
679  GList *nodes = NULL;
680 
681  n_data->stop = notify_entries_to_strings(n_data->stop,
682  &rsc_list, &node_list);
683  if ((strcmp(" ", (const char *) rsc_list->str) != 0)
684  && pcmk__str_eq(n_data->action, PCMK_ACTION_STOP, pcmk__str_none)) {
685  required = true;
686  }
687  add_notify_env_free_gs(n_data, "notify_stop_resource", rsc_list);
688  add_notify_env_free_gs(n_data, "notify_stop_uname", node_list);
689 
690  if ((n_data->start != NULL)
691  && pcmk__str_eq(n_data->action, PCMK_ACTION_START, pcmk__str_none)) {
692  required = true;
693  }
694  n_data->start = notify_entries_to_strings(n_data->start,
695  &rsc_list, &node_list);
696  add_notify_env_free_gs(n_data, "notify_start_resource", rsc_list);
697  add_notify_env_free_gs(n_data, "notify_start_uname", node_list);
698 
699  if ((n_data->demote != NULL)
700  && pcmk__str_eq(n_data->action, PCMK_ACTION_DEMOTE, pcmk__str_none)) {
701  required = true;
702  }
703  n_data->demote = notify_entries_to_strings(n_data->demote,
704  &rsc_list, &node_list);
705  add_notify_env_free_gs(n_data, "notify_demote_resource", rsc_list);
706  add_notify_env_free_gs(n_data, "notify_demote_uname", node_list);
707 
708  if ((n_data->promote != NULL)
709  && pcmk__str_eq(n_data->action, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
710  required = true;
711  }
712  n_data->promote = notify_entries_to_strings(n_data->promote,
713  &rsc_list, &node_list);
714  add_notify_env_free_gs(n_data, "notify_promote_resource", rsc_list);
715  add_notify_env_free_gs(n_data, "notify_promote_uname", node_list);
716 
717  n_data->active = notify_entries_to_strings(n_data->active,
718  &rsc_list, &node_list);
719  add_notify_env_free_gs(n_data, "notify_active_resource", rsc_list);
720  add_notify_env_free_gs(n_data, "notify_active_uname", node_list);
721 
722  n_data->unpromoted = notify_entries_to_strings(n_data->unpromoted,
723  &rsc_list, &node_list);
724  add_notify_env_gs(n_data, "notify_unpromoted_resource", rsc_list);
725  add_notify_env_gs(n_data, "notify_unpromoted_uname", node_list);
726 
727  // Deprecated: kept for backward compatibility with older resource agents
728  add_notify_env_free_gs(n_data, "notify_slave_resource", rsc_list);
729  add_notify_env_free_gs(n_data, "notify_slave_uname", node_list);
730 
731  n_data->promoted = notify_entries_to_strings(n_data->promoted,
732  &rsc_list, &node_list);
733  add_notify_env_gs(n_data, "notify_promoted_resource", rsc_list);
734  add_notify_env_gs(n_data, "notify_promoted_uname", node_list);
735 
736  // Deprecated: kept for backward compatibility with older resource agents
737  add_notify_env_free_gs(n_data, "notify_master_resource", rsc_list);
738  add_notify_env_free_gs(n_data, "notify_master_uname", node_list);
739 
740  n_data->inactive = notify_entries_to_strings(n_data->inactive,
741  &rsc_list, NULL);
742  add_notify_env_free_gs(n_data, "notify_inactive_resource", rsc_list);
743 
744  nodes = g_hash_table_get_values(n_data->allowed_nodes);
745  if (!pcmk__is_daemon) {
746  /* For display purposes, sort the node list, for consistent
747  * regression test output (while avoiding the performance hit
748  * for the live cluster).
749  */
750  nodes = g_list_sort(nodes, pe__cmp_node_name);
751  }
752  get_node_names(nodes, &node_list, NULL);
753  add_notify_env_free_gs(n_data, "notify_available_uname", node_list);
754  g_list_free(nodes);
755 
756  source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
757  if (pcmk__str_eq("host", source, pcmk__str_none)) {
758  get_node_names(rsc->cluster->nodes, &node_list, &metal_list);
759  add_notify_env_free_gs(n_data, "notify_all_hosts", metal_list);
760  } else {
761  get_node_names(rsc->cluster->nodes, &node_list, NULL);
762  }
763  add_notify_env_free_gs(n_data, "notify_all_uname", node_list);
764 
765  if (required && (n_data->pre != NULL)) {
768  }
769 
770  if (required && (n_data->post != NULL)) {
773  }
774 }
775 
776 /*
777  * \internal
778  * \brief Find any remote connection start relevant to an action
779  *
780  * \param[in] action Action to check
781  *
782  * \return If action is behind a remote connection, connection's start
783  */
784 static pcmk_action_t *
785 find_remote_start(pcmk_action_t *action)
786 {
787  if ((action != NULL) && (action->node != NULL)) {
788  pcmk_resource_t *remote_rsc = action->node->details->remote_rsc;
789 
790  if (remote_rsc != NULL) {
791  return find_first_action(remote_rsc->actions, NULL,
793  NULL);
794  }
795  }
796  return NULL;
797 }
798 
806 static void
807 create_notify_actions(pcmk_resource_t *rsc, notify_data_t *n_data)
808 {
809  GList *iter = NULL;
810  pcmk_action_t *stop = NULL;
811  pcmk_action_t *start = NULL;
812  enum action_tasks task = text2task(n_data->action);
813 
814  // If this is a clone, call recursively for each instance
815  if (rsc->children != NULL) {
816  g_list_foreach(rsc->children, (GFunc) create_notify_actions, n_data);
817  return;
818  }
819 
820  // Add notification meta-attributes to original actions
821  for (iter = rsc->actions; iter != NULL; iter = iter->next) {
822  pcmk_action_t *op = (pcmk_action_t *) iter->data;
823 
825  && (op->node != NULL)) {
826  switch (text2task(op->task)) {
827  case pcmk_action_start:
828  case pcmk_action_stop:
829  case pcmk_action_promote:
830  case pcmk_action_demote:
831  add_notify_data_to_action_meta(n_data, op);
832  break;
833  default:
834  break;
835  }
836  }
837  }
838 
839  // Skip notify action itself if original action was not needed
840  switch (task) {
841  case pcmk_action_start:
842  if (n_data->start == NULL) {
843  pe_rsc_trace(rsc, "No notify action needed for %s %s",
844  rsc->id, n_data->action);
845  return;
846  }
847  break;
848 
849  case pcmk_action_promote:
850  if (n_data->promote == NULL) {
851  pe_rsc_trace(rsc, "No notify action needed for %s %s",
852  rsc->id, n_data->action);
853  return;
854  }
855  break;
856 
857  case pcmk_action_demote:
858  if (n_data->demote == NULL) {
859  pe_rsc_trace(rsc, "No notify action needed for %s %s",
860  rsc->id, n_data->action);
861  return;
862  }
863  break;
864 
865  default:
866  // We cannot do same for stop because it might be implied by fencing
867  break;
868  }
869 
870  pe_rsc_trace(rsc, "Creating notify actions for %s %s",
871  rsc->id, n_data->action);
872 
873  // Create notify actions for stop or demote
874  if ((rsc->role != pcmk_role_stopped)
875  && ((task == pcmk_action_stop) || (task == pcmk_action_demote))) {
876 
877  stop = find_first_action(rsc->actions, NULL, PCMK_ACTION_STOP, NULL);
878 
879  for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
880  pcmk_node_t *current_node = (pcmk_node_t *) iter->data;
881 
882  /* If a stop is a pseudo-action implied by fencing, don't try to
883  * notify the node getting fenced.
884  */
885  if ((stop != NULL)
887  && (current_node->details->unclean
888  || current_node->details->remote_requires_reset)) {
889  continue;
890  }
891 
892  new_notify_action(rsc, current_node, n_data->pre,
893  n_data->pre_done, n_data);
894 
895  if ((task == pcmk_action_demote) || (stop == NULL)
897  new_post_notify_action(rsc, current_node, n_data);
898  }
899  }
900  }
901 
902  // Create notify actions for start or promote
903  if ((rsc->next_role != pcmk_role_stopped)
904  && ((task == pcmk_action_start) || (task == pcmk_action_promote))) {
905 
906  start = find_first_action(rsc->actions, NULL, PCMK_ACTION_START, NULL);
907  if (start != NULL) {
908  pcmk_action_t *remote_start = find_remote_start(start);
909 
910  if ((remote_start != NULL)
911  && !pcmk_is_set(remote_start->flags, pcmk_action_runnable)) {
912  /* Start and promote actions for a clone instance behind
913  * a Pacemaker Remote connection happen after the
914  * connection starts. If the connection start is blocked, do
915  * not schedule notifications for these actions.
916  */
917  return;
918  }
919  }
920  if (rsc->allocated_to == NULL) {
921  pe_proc_err("Next role '%s' but %s is not allocated",
922  role2text(rsc->next_role), rsc->id);
923  return;
924  }
925  if ((task != pcmk_action_start) || (start == NULL)
926  || pcmk_is_set(start->flags, pcmk_action_optional)) {
927 
928  new_notify_action(rsc, rsc->allocated_to, n_data->pre,
929  n_data->pre_done, n_data);
930  }
931  new_post_notify_action(rsc, rsc->allocated_to, n_data);
932  }
933 }
934 
942 void
944 {
945  if ((rsc == NULL) || (n_data == NULL)) {
946  return;
947  }
948  collect_resource_data(rsc, true, n_data);
949  add_notif_keys(rsc, n_data);
950  create_notify_actions(rsc, n_data);
951 }
952 
959 void
961 {
962  if (n_data == NULL) {
963  return;
964  }
965  g_list_free_full(n_data->stop, free);
966  g_list_free_full(n_data->start, free);
967  g_list_free_full(n_data->demote, free);
968  g_list_free_full(n_data->promote, free);
969  g_list_free_full(n_data->promoted, free);
970  g_list_free_full(n_data->unpromoted, free);
971  g_list_free_full(n_data->active, free);
972  g_list_free_full(n_data->inactive, free);
973  pcmk_free_nvpairs(n_data->keys);
974  free(n_data);
975 }
976 
991 void
993  pcmk_action_t *stonith_op)
994 {
995  notify_data_t *n_data;
996 
997  crm_info("Ordering notifications for implied %s after fencing", stop->uuid);
998  n_data = pe__action_notif_pseudo_ops(rsc, PCMK_ACTION_STOP, NULL,
999  stonith_op);
1000 
1001  if (n_data != NULL) {
1002  collect_resource_data(rsc, false, n_data);
1003  add_notify_env(n_data, "notify_stop_resource", rsc->id);
1004  add_notify_env(n_data, "notify_stop_uname", stop->node->details->uname);
1005  create_notify_actions(uber_parent(rsc), n_data);
1007  }
1008 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:238
Whether resource has clone notifications enabled.
Definition: resources.h:115
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition: resources.h:412
char * name
Definition: nvpair.h:30
#define INFINITY
Definition: crm.h:98
Whether action should not be executed.
Definition: actions.h:244
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:76
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:102
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition: complex.c:936
GHashTable * allowed_nodes
int priority
Definition: actions.h:398
Stopped.
Definition: roles.h:29
char * value
Definition: nvpair.h:31
enum rsc_role_e role
Resource&#39;s current role.
Definition: resources.h:468
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:146
GList * children
Resource&#39;s child resources, if any.
Definition: resources.h:475
#define add_notify_env_free_gs(n_data, key, value)
Definition: pe_notif.c:658
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition: utils.c:450
pcmk_action_t * pre
enum rsc_role_e next_role
Resource&#39;s scheduled next role.
Definition: resources.h:469
Implementation of pcmk_action_t.
Definition: actions.h:390
GHashTable * meta
Resource&#39;s meta-attributes.
Definition: resources.h:471
Promoted.
Definition: roles.h:32
action_tasks
Possible actions (including some pseudo-actions)
Definition: actions.h:79
enum action_tasks text2task(const char *task)
Definition: common.c:360
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:222
void pe__order_notifs_after_fencing(const pcmk_action_t *stop, pcmk_resource_t *rsc, pcmk_action_t *stonith_op)
Definition: pe_notif.c:992
#define add_notify_env_gs(n_data, key, value)
Definition: pe_notif.c:652
pcmk_resource_t * container
Resource containing this one, if any.
Definition: resources.h:480
pcmk_action_t * post
pcmk_action_t * pre_done
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:242
#define pe_proc_err(fmt...)
Definition: internal.h:49
gboolean remote_requires_reset
Definition: nodes.h:88
const char * action
Definition: pcmk_fence.c:30
GList * nodes
Nodes in cluster.
Definition: scheduler.h:195
const char * role2text(enum rsc_role_e role)
Definition: common.c:458
#define PCMK_ACTION_DEMOTE
Definition: actions.h:49
Promote.
Definition: actions.h:94
pcmk_node_t * node
Node to execute action on, if any.
Definition: actions.h:401
void pe__free_action_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:960
Implementation of pcmk_resource_t.
Definition: resources.h:399
Actions are ordered (optionally, if no other flags are set)
Demote.
Definition: actions.h:97
char * task
Action name.
Definition: actions.h:403
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:85
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:943
GHashTable * meta
Meta-attributes relevant to action.
Definition: actions.h:414
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:99
struct pe_node_shared_s * details
Basic node information.
Definition: nodes.h:134
#define PCMK_ACTION_START
Definition: actions.h:71
bool pcmk__is_daemon
Definition: logging.c:47
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition: resources.h:429
const char * uname
Node name in cluster.
Definition: nodes.h:68
Unpromoted.
Definition: roles.h:31
#define PCMK_ACTION_STOP
Definition: actions.h:74
GList * actions
Definition: resources.h:447
#define PCMK_ACTION_NOTIFIED
Definition: actions.h:60
char * uuid
Action key.
Definition: actions.h:404
pcmk_action_t * post_done
Implementation of pcmk_node_t.
Definition: nodes.h:130
#define PCMK_ACTION_CANCEL
Definition: actions.h:45
pcmk_action_t * custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler)
Create or update an action object.
Definition: pe_actions.c:1117
notify_data_t * pe__action_notif_pseudo_ops(pcmk_resource_t *rsc, const char *task, pcmk_action_t *action, pcmk_action_t *complete)
Definition: pe_notif.c:435
bool pe__is_guest_node(const pcmk_node_t *node)
Definition: remote.c:33
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: actions.c:183
Whether action is runnable.
Definition: actions.h:241
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:508
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
Definition: pe_actions.c:1486
#define crm_err(fmt, args...)
Definition: logging.h:381
Whether action does not require invoking an agent.
Definition: actions.h:238
#define CRM_ASSERT(expr)
Definition: results.h:42
Started.
Definition: roles.h:30
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:304
pcmk_node_t * allocated_to
Node resource is assigned to.
Definition: resources.h:451
#define PCMK_ACTION_PROMOTE
Definition: actions.h:65
GList * running_on
Nodes where resource may be active.
Definition: resources.h:460
enum pe_action_flags flags
Group of enum pe_action_flags.
Definition: actions.h:409
struct notify_entry_s notify_entry_t
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:37
const char * action
gboolean unclean
Whether node requires fencing.
Definition: nodes.h:76
#define crm_info(fmt, args...)
Definition: logging.h:384
#define add_notify_env(n_data, key, value)
Definition: pe_notif.c:647
gboolean online
Whether online.
Definition: nodes.h:72
pcmk_resource_t * remote_rsc
Remote connection resource for node, if it is a Pacemaker Remote node.
Definition: nodes.h:111
#define PCMK_ACTION_NOTIFY
Definition: actions.h:61
char * id
Resource ID in configuration.
Definition: resources.h:400
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition: resources.h:466