pacemaker  3.0.0-d8340737c4
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 IDs
83  return strcmp(entry_a->node->priv->id, entry_b->node->priv->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->priv->name == 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->priv->name);
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  const pcmk_resource_t *launcher = NULL;
145 
146  launcher = node->priv->remote->priv->launcher;
147  if (launcher->priv->active_nodes != NULL) {
148  node = pcmk__current_node(launcher);
149  if (node->priv->name == NULL) {
150  continue;
151  }
152  }
153  }
154  pcmk__add_word(host_node_names, 1024, node->priv->name);
155  }
156  }
157 
158  if ((all_node_names != NULL) && (*all_node_names == NULL)) {
159  *all_node_names = g_string_new(" ");
160  }
161  if ((host_node_names != NULL) && (*host_node_names == NULL)) {
162  *host_node_names = g_string_new(" ");
163  }
164 }
165 
180 static GList *
181 notify_entries_to_strings(GList *list, GString **rsc_names,
182  GString **node_names)
183 {
184  const char *last_rsc_id = NULL;
185 
186  // Initialize output lists to NULL
187  if (rsc_names != NULL) {
188  *rsc_names = NULL;
189  }
190  if (node_names != NULL) {
191  *node_names = NULL;
192  }
193 
194  // Sort input list for user-friendliness (and ease of filtering duplicates)
195  list = g_list_sort(list, compare_notify_entries);
196 
197  for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
198  notify_entry_t *entry = (notify_entry_t *) gIter->data;
199 
200  // Entry must have a resource (with ID)
201  CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
202  && (entry->rsc->id != NULL));
203  if ((entry == NULL) || (entry->rsc == NULL)
204  || (entry->rsc->id == NULL)) {
205  continue;
206  }
207 
208  // Entry must have a node unless listing inactive resources
209  CRM_LOG_ASSERT((node_names == NULL) || (entry->node != NULL));
210  if ((node_names != NULL) && (entry->node == NULL)) {
211  continue;
212  }
213 
214  // Don't add duplicates of a particular clone instance
215  if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
216  continue;
217  }
218  last_rsc_id = entry->rsc->id;
219 
220  if (rsc_names != NULL) {
221  pcmk__add_word(rsc_names, 1024, entry->rsc->id);
222  }
223  if ((node_names != NULL) && (entry->node->priv->name != NULL)) {
224  pcmk__add_word(node_names, 1024, entry->node->priv->name);
225  }
226  }
227 
228  // If there are no entries, return "empty" lists
229  if ((rsc_names != NULL) && (*rsc_names == NULL)) {
230  *rsc_names = g_string_new(" ");
231  }
232  if ((node_names != NULL) && (*node_names == NULL)) {
233  *node_names = g_string_new(" ");
234  }
235 
236  return list;
237 }
238 
247 static void
248 copy_meta_to_notify(gpointer key, gpointer value, gpointer user_data)
249 {
250  pcmk_action_t *notify = (pcmk_action_t *) user_data;
251 
252  /* Any existing meta-attributes (for example, the action timeout) are for
253  * the notify action itself, so don't override those.
254  */
255  if (g_hash_table_lookup(notify->meta, (const char *) key) != NULL) {
256  return;
257  }
258 
259  pcmk__insert_dup(notify->meta, (const char *) key, (const char *) value);
260 }
261 
262 static void
263 add_notify_data_to_action_meta(const notify_data_t *n_data,
265 {
266  for (const GSList *item = n_data->keys; item; item = item->next) {
267  const pcmk_nvpair_t *nvpair = (const pcmk_nvpair_t *) item->data;
268 
269  pcmk__insert_meta(action, nvpair->name, nvpair->value);
270  }
271 }
272 
284 static pcmk_action_t *
285 new_notify_pseudo_action(pcmk_resource_t *rsc, const pcmk_action_t *action,
286  const char *notif_action, const char *notif_type)
287 {
288  pcmk_action_t *notify = NULL;
289 
290  notify = custom_action(rsc,
291  pcmk__notify_key(rsc->id, notif_type, action->task),
292  notif_action, NULL,
294  rsc->priv->scheduler);
296  pcmk__insert_meta(notify, "notify_key_type", notif_type);
297  pcmk__insert_meta(notify, "notify_key_operation", action->task);
298  return notify;
299 }
300 
313 static pcmk_action_t *
314 new_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
315  pcmk_action_t *op, pcmk_action_t *notify_done,
316  const notify_data_t *n_data)
317 {
318  char *key = NULL;
319  pcmk_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, pcmk__action_runnable)) {
334  skip_reason = "original action not runnable";
335  }
336  if (skip_reason != NULL) {
337  pcmk__rsc_trace(rsc, "Skipping notify action for %s on %s: %s",
338  rsc->id, pcmk__node_name(node), 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  pcmk__rsc_trace(rsc, "Creating notify action for %s on %s (%s-%s)",
346  rsc->id, pcmk__node_name(node), 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  rsc->priv->scheduler);
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, pcmk__ar_ordered);
360  order_actions(notify_action, notify_done, pcmk__ar_ordered);
361  return notify_action;
362 }
363 
372 static void
373 new_post_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
374  notify_data_t *n_data)
375 {
376  pcmk_action_t *notify = NULL;
377 
378  pcmk__assert(n_data != NULL);
379 
380  // Create the "post-" notify action for specified instance
381  notify = new_notify_action(rsc, node, n_data->post, n_data->post_done,
382  n_data);
383  if (notify != NULL) {
384  notify->priority = PCMK_SCORE_INFINITY;
385  }
386 
387  // Order recurring monitors after all "post-" notifications complete
388  if (n_data->post_done == NULL) {
389  return;
390  }
391  for (GList *iter = rsc->priv->actions; iter != NULL; iter = iter->next) {
392  pcmk_action_t *mon = (pcmk_action_t *) iter->data;
393  const char *interval_ms_s = NULL;
394 
395  interval_ms_s = g_hash_table_lookup(mon->meta, PCMK_META_INTERVAL);
396  if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)
397  || pcmk__str_eq(mon->task, PCMK_ACTION_CANCEL, pcmk__str_none)) {
398  continue; // Not a recurring monitor
399  }
401  }
402 }
403 
437  pcmk_action_t *action, pcmk_action_t *complete)
438 {
439  notify_data_t *n_data = NULL;
440 
441  if (!pcmk_is_set(rsc->flags, pcmk__rsc_notify)) {
442  return NULL;
443  }
444 
445  n_data = pcmk__assert_alloc(1, sizeof(notify_data_t));
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  pcmk__insert_meta(n_data->pre, "notify_type", "pre");
456  pcmk__insert_meta(n_data->pre, "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  pcmk__insert_meta(n_data->pre_done, "notify_type", "pre");
464  pcmk__insert_meta(n_data->pre_done, "notify_operation", n_data->action);
465 
466  // Order "pre-" -> "pre-" complete -> original action
467  order_actions(n_data->pre, n_data->pre_done, pcmk__ar_ordered);
469  }
470 
471  if (complete != NULL) { // Need "post-" pseudo-actions
472 
473  // Create "post-" notify pseudo-action for clone
474  n_data->post = new_notify_pseudo_action(rsc, complete,
475  PCMK_ACTION_NOTIFY, "post");
476  n_data->post->priority = PCMK_SCORE_INFINITY;
477  if (pcmk_is_set(complete->flags, pcmk__action_runnable)) {
479  } else {
481  }
482  pcmk__insert_meta(n_data->post, "notify_type", "post");
483  pcmk__insert_meta(n_data->post, "notify_operation", n_data->action);
484 
485  // Create "post-" notifications complete pseudo-action for clone
486  n_data->post_done = new_notify_pseudo_action(rsc, complete,
488  "confirmed-post");
490  if (pcmk_is_set(complete->flags, pcmk__action_runnable)) {
492  } else {
494  }
495  pcmk__insert_meta(n_data->post_done, "notify_type", "post");
497  "notify_operation", n_data->action);
498 
499  // Order original action complete -> "post-" -> "post-" complete
500  order_actions(complete, n_data->post, pcmk__ar_first_implies_then);
501  order_actions(n_data->post, n_data->post_done,
503  }
504 
505  // If we created both, order "pre-" complete -> "post-"
506  if ((action != NULL) && (complete != NULL)) {
507  order_actions(n_data->pre_done, n_data->post, pcmk__ar_ordered);
508  }
509  return n_data;
510 }
511 
522 static notify_entry_t *
523 new_notify_entry(const pcmk_resource_t *rsc, const pcmk_node_t *node)
524 {
525  notify_entry_t *entry = pcmk__assert_alloc(1, sizeof(notify_entry_t));
526 
527  entry->rsc = rsc;
528  entry->node = node;
529  return entry;
530 }
531 
540 static void
541 collect_resource_data(pcmk_resource_t *rsc, bool activity,
542  notify_data_t *n_data)
543 {
544  const GList *iter = NULL;
545  notify_entry_t *entry = NULL;
546  const pcmk_node_t *node = NULL;
547 
548  if (n_data == NULL) {
549  return;
550  }
551 
552  if (n_data->allowed_nodes == NULL) {
553  n_data->allowed_nodes = rsc->priv->allowed_nodes;
554  }
555 
556  // If this is a clone, call recursively for each instance
557  if (rsc->priv->children != NULL) {
558  for (iter = rsc->priv->children; iter != NULL; iter = iter->next) {
559  pcmk_resource_t *child = iter->data;
560 
561  collect_resource_data(child, activity, n_data);
562  }
563  return;
564  }
565 
566  // This is a notification for a single clone instance
567 
568  if (rsc->priv->active_nodes != NULL) {
569  node = rsc->priv->active_nodes->data; // First is sufficient
570  }
571  entry = new_notify_entry(rsc, node);
572 
573  // Add notification indicating the resource state
574  switch (rsc->priv->orig_role) {
575  case pcmk_role_stopped:
576  n_data->inactive = g_list_prepend(n_data->inactive, entry);
577  break;
578 
579  case pcmk_role_started:
580  n_data->active = g_list_prepend(n_data->active, entry);
581  break;
582 
584  n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
585  n_data->active = g_list_prepend(n_data->active,
586  dup_notify_entry(entry));
587  break;
588 
589  case pcmk_role_promoted:
590  n_data->promoted = g_list_prepend(n_data->promoted, entry);
591  n_data->active = g_list_prepend(n_data->active,
592  dup_notify_entry(entry));
593  break;
594 
595  default:
597  "Resource %s role on %s (%s) is not supported for "
598  "notifications (bug?)",
599  rsc->id, pcmk__node_name(node),
600  pcmk_role_text(rsc->priv->orig_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->priv->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 pcmk__action_type task = pcmk__parse_action(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;
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->priv->meta,
758  if (pcmk__str_eq(PCMK_VALUE_HOST, source, pcmk__str_none)) {
759  get_node_names(rsc->priv->scheduler->nodes, &node_list, &metal_list);
760  add_notify_env_free_gs(n_data, "notify_all_hosts", metal_list);
761  } else {
762  get_node_names(rsc->priv->scheduler->nodes, &node_list, NULL);
763  }
764  add_notify_env_free_gs(n_data, "notify_all_uname", node_list);
765 
766  if (required && (n_data->pre != NULL)) {
769  }
770 
771  if (required && (n_data->post != NULL)) {
774  }
775 }
776 
777 /*
778  * \internal
779  * \brief Find any remote connection start relevant to an action
780  *
781  * \param[in] action Action to check
782  *
783  * \return If action is behind a remote connection, connection's start
784  */
785 static pcmk_action_t *
786 find_remote_start(pcmk_action_t *action)
787 {
788  if ((action != NULL) && (action->node != NULL)) {
789  pcmk_resource_t *remote_rsc = action->node->priv->remote;
790 
791  if (remote_rsc != NULL) {
792  return find_first_action(remote_rsc->priv->actions, NULL,
794  NULL);
795  }
796  }
797  return NULL;
798 }
799 
807 static void
808 create_notify_actions(pcmk_resource_t *rsc, notify_data_t *n_data)
809 {
810  GList *iter = NULL;
811  pcmk_action_t *stop = NULL;
812  pcmk_action_t *start = NULL;
813  enum pcmk__action_type task = pcmk__parse_action(n_data->action);
814 
815  // If this is a clone, call recursively for each instance
816  if (rsc->priv->children != NULL) {
817  g_list_foreach(rsc->priv->children, (GFunc) create_notify_actions,
818  n_data);
819  return;
820  }
821 
822  // Add notification meta-attributes to original actions
823  for (iter = rsc->priv->actions; iter != NULL; iter = iter->next) {
824  pcmk_action_t *op = (pcmk_action_t *) iter->data;
825 
827  && (op->node != NULL)) {
828  switch (pcmk__parse_action(op->task)) {
829  case pcmk__action_start:
830  case pcmk__action_stop:
832  case pcmk__action_demote:
833  add_notify_data_to_action_meta(n_data, op);
834  break;
835  default:
836  break;
837  }
838  }
839  }
840 
841  // Skip notify action itself if original action was not needed
842  switch (task) {
843  case pcmk__action_start:
844  if (n_data->start == NULL) {
845  pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
846  rsc->id, n_data->action);
847  return;
848  }
849  break;
850 
852  if (n_data->promote == NULL) {
853  pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
854  rsc->id, n_data->action);
855  return;
856  }
857  break;
858 
859  case pcmk__action_demote:
860  if (n_data->demote == NULL) {
861  pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
862  rsc->id, n_data->action);
863  return;
864  }
865  break;
866 
867  default:
868  // We cannot do same for stop because it might be implied by fencing
869  break;
870  }
871 
872  pcmk__rsc_trace(rsc, "Creating notify actions for %s %s",
873  rsc->id, n_data->action);
874 
875  // Create notify actions for stop or demote
876  if ((rsc->priv->orig_role != pcmk_role_stopped)
877  && ((task == pcmk__action_stop) || (task == pcmk__action_demote))) {
878 
879  stop = find_first_action(rsc->priv->actions, NULL, PCMK_ACTION_STOP,
880  NULL);
881 
882  for (iter = rsc->priv->active_nodes;
883  iter != NULL; iter = iter->next) {
884 
885  pcmk_node_t *current_node = (pcmk_node_t *) iter->data;
886 
887  /* If a stop is a pseudo-action implied by fencing, don't try to
888  * notify the node getting fenced.
889  */
890  if ((stop != NULL)
892  && (current_node->details->unclean
893  || pcmk_is_set(current_node->priv->flags,
895  continue;
896  }
897 
898  new_notify_action(rsc, current_node, n_data->pre,
899  n_data->pre_done, n_data);
900 
901  if ((task == pcmk__action_demote) || (stop == NULL)
903  new_post_notify_action(rsc, current_node, n_data);
904  }
905  }
906  }
907 
908  // Create notify actions for start or promote
909  if ((rsc->priv->next_role != pcmk_role_stopped)
910  && ((task == pcmk__action_start) || (task == pcmk__action_promote))) {
911 
912  start = find_first_action(rsc->priv->actions, NULL,
913  PCMK_ACTION_START, NULL);
914  if (start != NULL) {
915  pcmk_action_t *remote_start = find_remote_start(start);
916 
917  if ((remote_start != NULL)
918  && !pcmk_is_set(remote_start->flags, pcmk__action_runnable)) {
919  /* Start and promote actions for a clone instance behind
920  * a Pacemaker Remote connection happen after the
921  * connection starts. If the connection start is blocked, do
922  * not schedule notifications for these actions.
923  */
924  return;
925  }
926  }
927  if (rsc->priv->assigned_node == NULL) {
929  "Next role '%s' but %s is not allocated",
930  pcmk_role_text(rsc->priv->next_role), rsc->id);
931  return;
932  }
933  if ((task != pcmk__action_start) || (start == NULL)
935 
936  new_notify_action(rsc, rsc->priv->assigned_node, n_data->pre,
937  n_data->pre_done, n_data);
938  }
939  new_post_notify_action(rsc, rsc->priv->assigned_node, n_data);
940  }
941 }
942 
950 void
952 {
953  if ((rsc == NULL) || (n_data == NULL)) {
954  return;
955  }
956  collect_resource_data(rsc, true, n_data);
957  add_notif_keys(rsc, n_data);
958  create_notify_actions(rsc, n_data);
959 }
960 
967 void
969 {
970  if (n_data == NULL) {
971  return;
972  }
973  g_list_free_full(n_data->stop, free);
974  g_list_free_full(n_data->start, free);
975  g_list_free_full(n_data->demote, free);
976  g_list_free_full(n_data->promote, free);
977  g_list_free_full(n_data->promoted, free);
978  g_list_free_full(n_data->unpromoted, free);
979  g_list_free_full(n_data->active, free);
980  g_list_free_full(n_data->inactive, free);
981  pcmk_free_nvpairs(n_data->keys);
982  free(n_data);
983 }
984 
999 void
1001  pcmk_action_t *stonith_op)
1002 {
1003  notify_data_t *n_data;
1004 
1005  crm_info("Ordering notifications for implied %s after fencing", stop->uuid);
1006  n_data = pe__action_notif_pseudo_ops(rsc, PCMK_ACTION_STOP, NULL,
1007  stonith_op);
1008 
1009  if (n_data != NULL) {
1010  collect_resource_data(rsc, false, n_data);
1011  add_notify_env(n_data, "notify_stop_resource", rsc->id);
1012  add_notify_env(n_data, "notify_stop_uname", stop->node->priv->name);
1013  create_notify_actions(uber_parent(rsc), n_data);
1015  }
1016 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
pcmk__action_type
#define pcmk__sched_err(scheduler, fmt...)
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
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:1017
GHashTable * allowed_nodes
Stopped.
Definition: roles.h:36
char * value
Definition: nvpair.h:31
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:149
#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:658
pcmk_action_t * pre
#define pcmk__insert_meta(obj, name, value)
Promoted.
Definition: roles.h:39
gboolean unclean
Definition: nodes.h:58
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:196
void pe__order_notifs_after_fencing(const pcmk_action_t *stop, pcmk_resource_t *rsc, pcmk_action_t *stonith_op)
Definition: pe_notif.c:1000
#define add_notify_env_gs(n_data, key, value)
Definition: pe_notif.c:652
pcmk_action_t * post
pcmk_action_t * pre_done
const char * action
Definition: pcmk_fence.c:32
pcmk__node_private_t * priv
Definition: nodes.h:85
#define PCMK_VALUE_HOST
Definition: options.h:161
#define PCMK_ACTION_DEMOTE
Definition: actions.h:40
void pe__free_action_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:968
pcmk_scheduler_t * scheduler
Actions are ordered (optionally, if no other flags are set)
#define pcmk__clear_action_flags(action, flags_to_clear)
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:951
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
#define PCMK_ACTION_START
Definition: actions.h:63
pcmk__resource_private_t * priv
Definition: resources.h:61
bool pcmk__is_daemon
Definition: logging.c:47
Unpromoted.
Definition: roles.h:38
Wrappers for and extensions to libxml2.
#define PCMK_ACTION_STOP
Definition: actions.h:66
#define PCMK_ACTION_NOTIFIED
Definition: actions.h:52
pcmk_action_t * post_done
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
Definition: utils.c:465
#define PCMK_ACTION_CANCEL
Definition: actions.h:36
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:1093
#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:436
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: actions.c:335
pcmk_node_t * node
#define PCMK_META_INTERVAL
Definition: options.h:91
GList * nodes
Definition: scheduler.h:97
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:1416
pcmk_resource_t * remote
enum pcmk__action_type pcmk__parse_action(const char *action_name)
Definition: actions.c:90
pcmk_resource_t * launcher
Started.
Definition: roles.h:37
#define PCMK_ACTION_PROMOTE
Definition: actions.h:57
#define pcmk__set_action_flags(action, flags_to_set)
unsigned long long flags
Definition: resources.h:69
gboolean online
Definition: nodes.h:50
struct notify_entry_s notify_entry_t
GHashTable * meta
struct pcmk__node_details * details
Definition: nodes.h:82
const char * action
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
#define crm_info(fmt, args...)
Definition: logging.h:367
#define add_notify_env(n_data, key, value)
Definition: pe_notif.c:647
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:703
#define PCMK_ACTION_NOTIFY
Definition: actions.h:53
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition: scores.h:26