pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
pe_notif.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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/common/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 {
99 
100  dup->rsc = entry->rsc;
101  dup->node = entry->node;
102  return dup;
103 }
104 
118 static void
119 get_node_names(const GList *list, GString **all_node_names,
120  GString **host_node_names)
121 {
122  if (all_node_names != NULL) {
123  *all_node_names = NULL;
124  }
125  if (host_node_names != NULL) {
126  *host_node_names = NULL;
127  }
128 
129  for (const GList *iter = list; iter != NULL; iter = iter->next) {
130  const pcmk_node_t *node = (const pcmk_node_t *) iter->data;
131 
132  if (node->details->uname == NULL) {
133  continue;
134  }
135 
136  // Always add to list of all node names
137  if (all_node_names != NULL) {
138  pcmk__add_word(all_node_names, 1024, node->details->uname);
139  }
140 
141  // Add to host node name list if appropriate
142  if (host_node_names != NULL) {
143  if (pcmk__is_guest_or_bundle_node(node)
144  && (node->details->remote_rsc->container->running_on != NULL)) {
145  node = pcmk__current_node(node->details->remote_rsc->container);
146  if (node->details->uname == NULL) {
147  continue;
148  }
149  }
150  pcmk__add_word(host_node_names, 1024, node->details->uname);
151  }
152  }
153 
154  if ((all_node_names != NULL) && (*all_node_names == NULL)) {
155  *all_node_names = g_string_new(" ");
156  }
157  if ((host_node_names != NULL) && (*host_node_names == NULL)) {
158  *host_node_names = g_string_new(" ");
159  }
160 }
161 
176 static GList *
177 notify_entries_to_strings(GList *list, GString **rsc_names,
178  GString **node_names)
179 {
180  const char *last_rsc_id = NULL;
181 
182  // Initialize output lists to NULL
183  if (rsc_names != NULL) {
184  *rsc_names = NULL;
185  }
186  if (node_names != NULL) {
187  *node_names = NULL;
188  }
189 
190  // Sort input list for user-friendliness (and ease of filtering duplicates)
191  list = g_list_sort(list, compare_notify_entries);
192 
193  for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
194  notify_entry_t *entry = (notify_entry_t *) gIter->data;
195 
196  // Entry must have a resource (with ID)
197  CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
198  && (entry->rsc->id != NULL));
199  if ((entry == NULL) || (entry->rsc == NULL)
200  || (entry->rsc->id == NULL)) {
201  continue;
202  }
203 
204  // Entry must have a node unless listing inactive resources
205  CRM_LOG_ASSERT((node_names == NULL) || (entry->node != NULL));
206  if ((node_names != NULL) && (entry->node == NULL)) {
207  continue;
208  }
209 
210  // Don't add duplicates of a particular clone instance
211  if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
212  continue;
213  }
214  last_rsc_id = entry->rsc->id;
215 
216  if (rsc_names != NULL) {
217  pcmk__add_word(rsc_names, 1024, entry->rsc->id);
218  }
219  if ((node_names != NULL) && (entry->node->details->uname != NULL)) {
220  pcmk__add_word(node_names, 1024, entry->node->details->uname);
221  }
222  }
223 
224  // If there are no entries, return "empty" lists
225  if ((rsc_names != NULL) && (*rsc_names == NULL)) {
226  *rsc_names = g_string_new(" ");
227  }
228  if ((node_names != NULL) && (*node_names == NULL)) {
229  *node_names = g_string_new(" ");
230  }
231 
232  return list;
233 }
234 
243 static void
244 copy_meta_to_notify(gpointer key, gpointer value, gpointer user_data)
245 {
246  pcmk_action_t *notify = (pcmk_action_t *) user_data;
247 
248  /* Any existing meta-attributes (for example, the action timeout) are for
249  * the notify action itself, so don't override those.
250  */
251  if (g_hash_table_lookup(notify->meta, (const char *) key) != NULL) {
252  return;
253  }
254 
255  pcmk__insert_dup(notify->meta, (const char *) key, (const char *) value);
256 }
257 
258 static void
259 add_notify_data_to_action_meta(const notify_data_t *n_data,
261 {
262  for (const GSList *item = n_data->keys; item; item = item->next) {
263  const pcmk_nvpair_t *nvpair = (const pcmk_nvpair_t *) item->data;
264 
265  pcmk__insert_meta(action, nvpair->name, nvpair->value);
266  }
267 }
268 
280 static pcmk_action_t *
281 new_notify_pseudo_action(pcmk_resource_t *rsc, const pcmk_action_t *action,
282  const char *notif_action, const char *notif_type)
283 {
284  pcmk_action_t *notify = NULL;
285 
286  notify = custom_action(rsc,
287  pcmk__notify_key(rsc->id, notif_type, action->task),
288  notif_action, NULL,
290  rsc->cluster);
292  pcmk__insert_meta(notify, "notify_key_type", notif_type);
293  pcmk__insert_meta(notify, "notify_key_operation", action->task);
294  return notify;
295 }
296 
309 static pcmk_action_t *
310 new_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
311  pcmk_action_t *op, pcmk_action_t *notify_done,
312  const notify_data_t *n_data)
313 {
314  char *key = NULL;
315  pcmk_action_t *notify_action = NULL;
316  const char *value = NULL;
317  const char *task = NULL;
318  const char *skip_reason = NULL;
319 
320  CRM_CHECK((rsc != NULL) && (node != NULL), return NULL);
321 
322  // Ensure we have all the info we need
323  if (op == NULL) {
324  skip_reason = "no action";
325  } else if (notify_done == NULL) {
326  skip_reason = "no parent notification";
327  } else if (!node->details->online) {
328  skip_reason = "node offline";
329  } else if (!pcmk_is_set(op->flags, pcmk_action_runnable)) {
330  skip_reason = "original action not runnable";
331  }
332  if (skip_reason != NULL) {
333  pcmk__rsc_trace(rsc, "Skipping notify action for %s on %s: %s",
334  rsc->id, pcmk__node_name(node), skip_reason);
335  return NULL;
336  }
337 
338  value = g_hash_table_lookup(op->meta, "notify_type"); // "pre" or "post"
339  task = g_hash_table_lookup(op->meta, "notify_operation"); // original action
340 
341  pcmk__rsc_trace(rsc, "Creating notify action for %s on %s (%s-%s)",
342  rsc->id, pcmk__node_name(node), value, task);
343 
344  // Create the notify action
345  key = pcmk__notify_key(rsc->id, value, task);
346  notify_action = custom_action(rsc, key, op->task, node,
348  rsc->cluster);
349 
350  // Add meta-data to notify action
351  g_hash_table_foreach(op->meta, copy_meta_to_notify, notify_action);
352  add_notify_data_to_action_meta(n_data, notify_action);
353 
354  // Order notify after original action and before parent notification
355  order_actions(op, notify_action, pcmk__ar_ordered);
356  order_actions(notify_action, notify_done, pcmk__ar_ordered);
357  return notify_action;
358 }
359 
368 static void
369 new_post_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
370  notify_data_t *n_data)
371 {
372  pcmk_action_t *notify = NULL;
373 
374  pcmk__assert(n_data != NULL);
375 
376  // Create the "post-" notify action for specified instance
377  notify = new_notify_action(rsc, node, n_data->post, n_data->post_done,
378  n_data);
379  if (notify != NULL) {
380  notify->priority = PCMK_SCORE_INFINITY;
381  }
382 
383  // Order recurring monitors after all "post-" notifications complete
384  if (n_data->post_done == NULL) {
385  return;
386  }
387  for (GList *iter = rsc->actions; iter != NULL; iter = iter->next) {
388  pcmk_action_t *mon = (pcmk_action_t *) iter->data;
389  const char *interval_ms_s = NULL;
390 
391  interval_ms_s = g_hash_table_lookup(mon->meta, PCMK_META_INTERVAL);
392  if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)
393  || pcmk__str_eq(mon->task, PCMK_ACTION_CANCEL, pcmk__str_none)) {
394  continue; // Not a recurring monitor
395  }
397  }
398 }
399 
433  pcmk_action_t *action, pcmk_action_t *complete)
434 {
435  notify_data_t *n_data = NULL;
436 
437  if (!pcmk_is_set(rsc->flags, pcmk_rsc_notify)) {
438  return NULL;
439  }
440 
441  n_data = pcmk__assert_alloc(1, sizeof(notify_data_t));
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, PCMK_ACTION_NOTIFY,
449  "pre");
451  pcmk__insert_meta(n_data->pre, "notify_type", "pre");
452  pcmk__insert_meta(n_data->pre, "notify_operation", n_data->action);
453 
454  // Create "pre-" notifications complete pseudo-action for clone
455  n_data->pre_done = new_notify_pseudo_action(rsc, action,
457  "confirmed-pre");
459  pcmk__insert_meta(n_data->pre_done, "notify_type", "pre");
460  pcmk__insert_meta(n_data->pre_done, "notify_operation", n_data->action);
461 
462  // Order "pre-" -> "pre-" complete -> original action
463  order_actions(n_data->pre, n_data->pre_done, pcmk__ar_ordered);
465  }
466 
467  if (complete != NULL) { // Need "post-" pseudo-actions
468 
469  // Create "post-" notify pseudo-action for clone
470  n_data->post = new_notify_pseudo_action(rsc, complete,
471  PCMK_ACTION_NOTIFY, "post");
472  n_data->post->priority = PCMK_SCORE_INFINITY;
473  if (pcmk_is_set(complete->flags, pcmk_action_runnable)) {
475  } else {
477  }
478  pcmk__insert_meta(n_data->post, "notify_type", "post");
479  pcmk__insert_meta(n_data->post, "notify_operation", n_data->action);
480 
481  // Create "post-" notifications complete pseudo-action for clone
482  n_data->post_done = new_notify_pseudo_action(rsc, complete,
484  "confirmed-post");
486  if (pcmk_is_set(complete->flags, pcmk_action_runnable)) {
488  } else {
490  }
491  pcmk__insert_meta(n_data->post_done, "notify_type", "post");
493  "notify_operation", n_data->action);
494 
495  // Order original action complete -> "post-" -> "post-" complete
496  order_actions(complete, n_data->post, pcmk__ar_first_implies_then);
497  order_actions(n_data->post, n_data->post_done,
499  }
500 
501  // If we created both, order "pre-" complete -> "post-"
502  if ((action != NULL) && (complete != NULL)) {
503  order_actions(n_data->pre_done, n_data->post, pcmk__ar_ordered);
504  }
505  return n_data;
506 }
507 
518 static notify_entry_t *
519 new_notify_entry(const pcmk_resource_t *rsc, const pcmk_node_t *node)
520 {
521  notify_entry_t *entry = pcmk__assert_alloc(1, sizeof(notify_entry_t));
522 
523  entry->rsc = rsc;
524  entry->node = node;
525  return entry;
526 }
527 
536 static void
537 collect_resource_data(const pcmk_resource_t *rsc, bool activity,
538  notify_data_t *n_data)
539 {
540  const GList *iter = NULL;
541  notify_entry_t *entry = NULL;
542  const pcmk_node_t *node = NULL;
543 
544  if (n_data == NULL) {
545  return;
546  }
547 
548  if (n_data->allowed_nodes == NULL) {
549  n_data->allowed_nodes = rsc->allowed_nodes;
550  }
551 
552  // If this is a clone, call recursively for each instance
553  if (rsc->children != NULL) {
554  for (iter = rsc->children; iter != NULL; iter = iter->next) {
555  const pcmk_resource_t *child = (const pcmk_resource_t *) iter->data;
556 
557  collect_resource_data(child, activity, n_data);
558  }
559  return;
560  }
561 
562  // This is a notification for a single clone instance
563 
564  if (rsc->running_on != NULL) {
565  node = rsc->running_on->data; // First is sufficient
566  }
567  entry = new_notify_entry(rsc, node);
568 
569  // Add notification indicating the resource state
570  switch (rsc->role) {
571  case pcmk_role_stopped:
572  n_data->inactive = g_list_prepend(n_data->inactive, entry);
573  break;
574 
575  case pcmk_role_started:
576  n_data->active = g_list_prepend(n_data->active, entry);
577  break;
578 
580  n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
581  n_data->active = g_list_prepend(n_data->active,
582  dup_notify_entry(entry));
583  break;
584 
585  case pcmk_role_promoted:
586  n_data->promoted = g_list_prepend(n_data->promoted, entry);
587  n_data->active = g_list_prepend(n_data->active,
588  dup_notify_entry(entry));
589  break;
590 
591  default:
592  pcmk__sched_err("Resource %s role on %s (%s) is not supported for "
593  "notifications (bug?)",
594  rsc->id, pcmk__node_name(node),
595  pcmk_role_text(rsc->role));
596  free(entry);
597  break;
598  }
599 
600  if (!activity) {
601  return;
602  }
603 
604  // Add notification entries for each of the resource's actions
605  for (iter = rsc->actions; iter != NULL; iter = iter->next) {
606  const pcmk_action_t *op = (const pcmk_action_t *) iter->data;
607 
609  && (op->node != NULL)) {
610  enum action_tasks task = pcmk_parse_action(op->task);
611 
612  if ((task == pcmk_action_stop) && op->node->details->unclean) {
613  // Create anyway (additional noise if node can't be fenced)
614  } else if (!pcmk_is_set(op->flags, pcmk_action_runnable)) {
615  continue;
616  }
617 
618  entry = new_notify_entry(rsc, op->node);
619 
620  switch (task) {
621  case pcmk_action_start:
622  n_data->start = g_list_prepend(n_data->start, entry);
623  break;
624  case pcmk_action_stop:
625  n_data->stop = g_list_prepend(n_data->stop, entry);
626  break;
627  case pcmk_action_promote:
628  n_data->promote = g_list_prepend(n_data->promote, entry);
629  break;
630  case pcmk_action_demote:
631  n_data->demote = g_list_prepend(n_data->demote, entry);
632  break;
633  default:
634  free(entry);
635  break;
636  }
637  }
638  }
639 }
640 
641 // For (char *) value
642 #define add_notify_env(n_data, key, value) do { \
643  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
644  } while (0)
645 
646 // For (GString *) value
647 #define add_notify_env_gs(n_data, key, value) do { \
648  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
649  (const char *) value->str); \
650  } while (0)
651 
652 // For (GString *) value
653 #define add_notify_env_free_gs(n_data, key, value) do { \
654  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
655  (const char *) value->str); \
656  g_string_free(value, TRUE); value = NULL; \
657  } while (0)
658 
666 static void
667 add_notif_keys(const pcmk_resource_t *rsc, notify_data_t *n_data)
668 {
669  bool required = false; // Whether to make notify actions required
670  GString *rsc_list = NULL;
671  GString *node_list = NULL;
672  GString *metal_list = NULL;
673  const char *source = NULL;
674  GList *nodes = NULL;
675 
676  n_data->stop = notify_entries_to_strings(n_data->stop,
677  &rsc_list, &node_list);
678  if ((strcmp(" ", (const char *) rsc_list->str) != 0)
679  && pcmk__str_eq(n_data->action, PCMK_ACTION_STOP, pcmk__str_none)) {
680  required = true;
681  }
682  add_notify_env_free_gs(n_data, "notify_stop_resource", rsc_list);
683  add_notify_env_free_gs(n_data, "notify_stop_uname", node_list);
684 
685  if ((n_data->start != NULL)
686  && pcmk__str_eq(n_data->action, PCMK_ACTION_START, pcmk__str_none)) {
687  required = true;
688  }
689  n_data->start = notify_entries_to_strings(n_data->start,
690  &rsc_list, &node_list);
691  add_notify_env_free_gs(n_data, "notify_start_resource", rsc_list);
692  add_notify_env_free_gs(n_data, "notify_start_uname", node_list);
693 
694  if ((n_data->demote != NULL)
695  && pcmk__str_eq(n_data->action, PCMK_ACTION_DEMOTE, pcmk__str_none)) {
696  required = true;
697  }
698  n_data->demote = notify_entries_to_strings(n_data->demote,
699  &rsc_list, &node_list);
700  add_notify_env_free_gs(n_data, "notify_demote_resource", rsc_list);
701  add_notify_env_free_gs(n_data, "notify_demote_uname", node_list);
702 
703  if ((n_data->promote != NULL)
704  && pcmk__str_eq(n_data->action, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
705  required = true;
706  }
707  n_data->promote = notify_entries_to_strings(n_data->promote,
708  &rsc_list, &node_list);
709  add_notify_env_free_gs(n_data, "notify_promote_resource", rsc_list);
710  add_notify_env_free_gs(n_data, "notify_promote_uname", node_list);
711 
712  n_data->active = notify_entries_to_strings(n_data->active,
713  &rsc_list, &node_list);
714  add_notify_env_free_gs(n_data, "notify_active_resource", rsc_list);
715  add_notify_env_free_gs(n_data, "notify_active_uname", node_list);
716 
717  n_data->unpromoted = notify_entries_to_strings(n_data->unpromoted,
718  &rsc_list, &node_list);
719  add_notify_env_gs(n_data, "notify_unpromoted_resource", rsc_list);
720  add_notify_env_gs(n_data, "notify_unpromoted_uname", node_list);
721 
722  // Deprecated: kept for backward compatibility with older resource agents
723  add_notify_env_free_gs(n_data, "notify_slave_resource", rsc_list);
724  add_notify_env_free_gs(n_data, "notify_slave_uname", node_list);
725 
726  n_data->promoted = notify_entries_to_strings(n_data->promoted,
727  &rsc_list, &node_list);
728  add_notify_env_gs(n_data, "notify_promoted_resource", rsc_list);
729  add_notify_env_gs(n_data, "notify_promoted_uname", node_list);
730 
731  // Deprecated: kept for backward compatibility with older resource agents
732  add_notify_env_free_gs(n_data, "notify_master_resource", rsc_list);
733  add_notify_env_free_gs(n_data, "notify_master_uname", node_list);
734 
735  n_data->inactive = notify_entries_to_strings(n_data->inactive,
736  &rsc_list, NULL);
737  add_notify_env_free_gs(n_data, "notify_inactive_resource", rsc_list);
738 
739  nodes = g_hash_table_get_values(n_data->allowed_nodes);
740  if (!pcmk__is_daemon) {
741  /* For display purposes, sort the node list, for consistent
742  * regression test output (while avoiding the performance hit
743  * for the live cluster).
744  */
745  nodes = g_list_sort(nodes, pe__cmp_node_name);
746  }
747  get_node_names(nodes, &node_list, NULL);
748  add_notify_env_free_gs(n_data, "notify_available_uname", node_list);
749  g_list_free(nodes);
750 
751  source = g_hash_table_lookup(rsc->meta,
753  if (pcmk__str_eq(PCMK_VALUE_HOST, source, pcmk__str_none)) {
754  get_node_names(rsc->cluster->nodes, &node_list, &metal_list);
755  add_notify_env_free_gs(n_data, "notify_all_hosts", metal_list);
756  } else {
757  get_node_names(rsc->cluster->nodes, &node_list, NULL);
758  }
759  add_notify_env_free_gs(n_data, "notify_all_uname", node_list);
760 
761  if (required && (n_data->pre != NULL)) {
764  }
765 
766  if (required && (n_data->post != NULL)) {
769  }
770 }
771 
772 /*
773  * \internal
774  * \brief Find any remote connection start relevant to an action
775  *
776  * \param[in] action Action to check
777  *
778  * \return If action is behind a remote connection, connection's start
779  */
780 static pcmk_action_t *
781 find_remote_start(pcmk_action_t *action)
782 {
783  if ((action != NULL) && (action->node != NULL)) {
784  pcmk_resource_t *remote_rsc = action->node->details->remote_rsc;
785 
786  if (remote_rsc != NULL) {
787  return find_first_action(remote_rsc->actions, NULL,
789  NULL);
790  }
791  }
792  return NULL;
793 }
794 
802 static void
803 create_notify_actions(pcmk_resource_t *rsc, notify_data_t *n_data)
804 {
805  GList *iter = NULL;
806  pcmk_action_t *stop = NULL;
807  pcmk_action_t *start = NULL;
808  enum action_tasks task = pcmk_parse_action(n_data->action);
809 
810  // If this is a clone, call recursively for each instance
811  if (rsc->children != NULL) {
812  g_list_foreach(rsc->children, (GFunc) create_notify_actions, n_data);
813  return;
814  }
815 
816  // Add notification meta-attributes to original actions
817  for (iter = rsc->actions; iter != NULL; iter = iter->next) {
818  pcmk_action_t *op = (pcmk_action_t *) iter->data;
819 
821  && (op->node != NULL)) {
822  switch (pcmk_parse_action(op->task)) {
823  case pcmk_action_start:
824  case pcmk_action_stop:
825  case pcmk_action_promote:
826  case pcmk_action_demote:
827  add_notify_data_to_action_meta(n_data, op);
828  break;
829  default:
830  break;
831  }
832  }
833  }
834 
835  // Skip notify action itself if original action was not needed
836  switch (task) {
837  case pcmk_action_start:
838  if (n_data->start == NULL) {
839  pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
840  rsc->id, n_data->action);
841  return;
842  }
843  break;
844 
845  case pcmk_action_promote:
846  if (n_data->promote == NULL) {
847  pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
848  rsc->id, n_data->action);
849  return;
850  }
851  break;
852 
853  case pcmk_action_demote:
854  if (n_data->demote == NULL) {
855  pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
856  rsc->id, n_data->action);
857  return;
858  }
859  break;
860 
861  default:
862  // We cannot do same for stop because it might be implied by fencing
863  break;
864  }
865 
866  pcmk__rsc_trace(rsc, "Creating notify actions for %s %s",
867  rsc->id, n_data->action);
868 
869  // Create notify actions for stop or demote
870  if ((rsc->role != pcmk_role_stopped)
871  && ((task == pcmk_action_stop) || (task == pcmk_action_demote))) {
872 
873  stop = find_first_action(rsc->actions, NULL, PCMK_ACTION_STOP, NULL);
874 
875  for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
876  pcmk_node_t *current_node = (pcmk_node_t *) iter->data;
877 
878  /* If a stop is a pseudo-action implied by fencing, don't try to
879  * notify the node getting fenced.
880  */
881  if ((stop != NULL)
883  && (current_node->details->unclean
884  || current_node->details->remote_requires_reset)) {
885  continue;
886  }
887 
888  new_notify_action(rsc, current_node, n_data->pre,
889  n_data->pre_done, n_data);
890 
891  if ((task == pcmk_action_demote) || (stop == NULL)
893  new_post_notify_action(rsc, current_node, n_data);
894  }
895  }
896  }
897 
898  // Create notify actions for start or promote
899  if ((rsc->next_role != pcmk_role_stopped)
900  && ((task == pcmk_action_start) || (task == pcmk_action_promote))) {
901 
902  start = find_first_action(rsc->actions, NULL, PCMK_ACTION_START, NULL);
903  if (start != NULL) {
904  pcmk_action_t *remote_start = find_remote_start(start);
905 
906  if ((remote_start != NULL)
907  && !pcmk_is_set(remote_start->flags, pcmk_action_runnable)) {
908  /* Start and promote actions for a clone instance behind
909  * a Pacemaker Remote connection happen after the
910  * connection starts. If the connection start is blocked, do
911  * not schedule notifications for these actions.
912  */
913  return;
914  }
915  }
916  if (rsc->allocated_to == NULL) {
917  pcmk__sched_err("Next role '%s' but %s is not allocated",
918  pcmk_role_text(rsc->next_role), rsc->id);
919  return;
920  }
921  if ((task != pcmk_action_start) || (start == NULL)
922  || pcmk_is_set(start->flags, pcmk_action_optional)) {
923 
924  new_notify_action(rsc, rsc->allocated_to, n_data->pre,
925  n_data->pre_done, n_data);
926  }
927  new_post_notify_action(rsc, rsc->allocated_to, n_data);
928  }
929 }
930 
938 void
940 {
941  if ((rsc == NULL) || (n_data == NULL)) {
942  return;
943  }
944  collect_resource_data(rsc, true, n_data);
945  add_notif_keys(rsc, n_data);
946  create_notify_actions(rsc, n_data);
947 }
948 
955 void
957 {
958  if (n_data == NULL) {
959  return;
960  }
961  g_list_free_full(n_data->stop, free);
962  g_list_free_full(n_data->start, free);
963  g_list_free_full(n_data->demote, free);
964  g_list_free_full(n_data->promote, free);
965  g_list_free_full(n_data->promoted, free);
966  g_list_free_full(n_data->unpromoted, free);
967  g_list_free_full(n_data->active, free);
968  g_list_free_full(n_data->inactive, free);
969  pcmk_free_nvpairs(n_data->keys);
970  free(n_data);
971 }
972 
987 void
989  pcmk_action_t *stonith_op)
990 {
991  notify_data_t *n_data;
992 
993  crm_info("Ordering notifications for implied %s after fencing", stop->uuid);
994  n_data = pe__action_notif_pseudo_ops(rsc, PCMK_ACTION_STOP, NULL,
995  stonith_op);
996 
997  if (n_data != NULL) {
998  collect_resource_data(rsc, false, n_data);
999  add_notify_env(n_data, "notify_stop_resource", rsc->id);
1000  add_notify_env(n_data, "notify_stop_uname", stop->node->details->uname);
1001  create_notify_actions(uber_parent(rsc), n_data);
1003  }
1004 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
pcmk_scheduler_t * cluster
Definition: resources.h:408
char * name
Definition: nvpair.h:30
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition: roles.c:23
enum action_tasks pcmk_parse_action(const char *action_name)
Parse an action type from an action name.
Definition: actions.c:92
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:103
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition: complex.c:1046
GHashTable * allowed_nodes
int priority
Definition: actions.h:338
Stopped.
Definition: roles.h:36
char * value
Definition: nvpair.h:31
enum rsc_role_e role
Definition: resources.h:464
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:145
GList * children
Definition: resources.h:471
#define pcmk__rsc_trace(rsc, fmt, args...)
#define PCMK_META_CONTAINER_ATTRIBUTE_TARGET
Definition: options.h:85
#define add_notify_env_free_gs(n_data, key, value)
Definition: pe_notif.c:653
pcmk_action_t * pre
enum rsc_role_e next_role
Definition: resources.h:465
#define pcmk__insert_meta(obj, name, value)
GHashTable * meta
Definition: resources.h:467
Promoted.
Definition: roles.h:39
action_tasks
Definition: actions.h:83
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:228
void pe__order_notifs_after_fencing(const pcmk_action_t *stop, pcmk_resource_t *rsc, pcmk_action_t *stonith_op)
Definition: pe_notif.c:988
#define add_notify_env_gs(n_data, key, value)
Definition: pe_notif.c:647
pcmk_resource_t * container
Definition: resources.h:476
pcmk_action_t * post
pcmk_action_t * pre_done
gboolean remote_requires_reset
Definition: nodes.h:113
const char * action
Definition: pcmk_fence.c:30
#define PCMK_VALUE_HOST
Definition: options.h:160
#define PCMK_ACTION_DEMOTE
Definition: actions.h:49
pcmk_node_t * node
Definition: actions.h:341
void pe__free_action_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:956
Actions are ordered (optionally, if no other flags are set)
#define pcmk__clear_action_flags(action, flags_to_clear)
#define pcmk__sched_err(fmt...)
char * task
Definition: actions.h:343
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:939
GHashTable * meta
Definition: actions.h:354
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:94
struct pe_node_shared_s * details
Definition: nodes.h:168
#define PCMK_ACTION_START
Definition: actions.h:72
bool pcmk__is_daemon
Definition: logging.c:47
unsigned long long flags
Definition: resources.h:428
const char * uname
Definition: nodes.h:74
Unpromoted.
Definition: roles.h:38
Wrappers for and extensions to libxml2.
#define PCMK_ACTION_STOP
Definition: actions.h:75
GList * actions
Definition: resources.h:444
#define PCMK_ACTION_NOTIFIED
Definition: actions.h:61
char * uuid
Definition: actions.h:344
pcmk_action_t * post_done
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
Definition: utils.c:457
#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:1129
#define pcmk__assert(expr)
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:432
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: actions.c:336
#define PCMK_META_INTERVAL
Definition: options.h:91
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:1451
Started.
Definition: roles.h:37
pcmk_node_t * allocated_to
Definition: resources.h:447
#define PCMK_ACTION_PROMOTE
Definition: actions.h:66
GList * running_on
Definition: resources.h:456
enum pe_action_flags flags
Definition: actions.h:349
#define pcmk__set_action_flags(action, flags_to_set)
struct notify_entry_s notify_entry_t
const char * action
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:297
gboolean unclean
Definition: nodes.h:92
#define crm_info(fmt, args...)
Definition: logging.h:399
#define add_notify_env(n_data, key, value)
Definition: pe_notif.c:642
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:713
gboolean online
Definition: nodes.h:81
pcmk_resource_t * remote_rsc
Definition: nodes.h:136
#define PCMK_ACTION_NOTIFY
Definition: actions.h:62
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition: scores.h:24
GHashTable * allowed_nodes
Definition: resources.h:462