pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
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
14#include <pacemaker-internal.h>
15
16#include "pe_status_private.h"
17
18typedef struct notify_entry_s {
19 const pcmk_resource_t *rsc;
20 const pcmk_node_t *node;
22
36static gint
37compare_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
95static notify_entry_t *
96dup_notify_entry(const notify_entry_t *entry)
97{
99
100 dup->rsc = entry->rsc;
101 dup->node = entry->node;
102 return dup;
103}
104
118static void
119get_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 /* @TODO This breaks the comparability of the various notification
134 * variables and thus any agent relying on it. Maybe add "UNKNOWN"
135 * or something like that.
136 */
137 continue;
138 }
139
140 // Always add to list of all node names
141 if (all_node_names != NULL) {
142 pcmk__add_word(all_node_names, 1024, node->priv->name);
143 }
144
145 // Add to host node name list if appropriate
146 if (host_node_names != NULL) {
147 if (pcmk__is_guest_or_bundle_node(node)) {
148 const pcmk_resource_t *launcher = NULL;
149
150 launcher = node->priv->remote->priv->launcher;
151 if (launcher->priv->active_nodes != NULL) {
152 node = pcmk__current_node(launcher);
153 if (node->priv->name == NULL) {
154 continue;
155 }
156 }
157 }
158 pcmk__add_word(host_node_names, 1024, node->priv->name);
159 }
160 }
161
162 if ((all_node_names != NULL) && (*all_node_names == NULL)) {
163 *all_node_names = g_string_new(" ");
164 }
165 if ((host_node_names != NULL) && (*host_node_names == NULL)) {
166 *host_node_names = g_string_new(" ");
167 }
168}
169
184static GList *
185notify_entries_to_strings(GList *list, GString **rsc_names,
186 GString **node_names)
187{
188 const char *last_rsc_id = NULL;
189
190 // Initialize output lists to NULL
191 if (rsc_names != NULL) {
192 *rsc_names = NULL;
193 }
194 if (node_names != NULL) {
195 *node_names = NULL;
196 }
197
198 // Sort input list for user-friendliness (and ease of filtering duplicates)
199 list = g_list_sort(list, compare_notify_entries);
200
201 for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
202 notify_entry_t *entry = (notify_entry_t *) gIter->data;
203
204 // Entry must have a resource (with ID)
205 CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
206 && (entry->rsc->id != NULL));
207 if ((entry == NULL) || (entry->rsc == NULL)
208 || (entry->rsc->id == NULL)) {
209 continue;
210 }
211
212 // Entry must have a node unless listing inactive resources
213 CRM_LOG_ASSERT((node_names == NULL) || (entry->node != NULL));
214 if ((node_names != NULL) && (entry->node == NULL)) {
215 continue;
216 }
217
218 // Don't add duplicates of a particular clone instance
219 if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
220 continue;
221 }
222 last_rsc_id = entry->rsc->id;
223
224 if (rsc_names != NULL) {
225 pcmk__add_word(rsc_names, 1024, entry->rsc->id);
226 }
227 if ((node_names != NULL) && (entry->node->priv->name != NULL)) {
228 pcmk__add_word(node_names, 1024, entry->node->priv->name);
229 }
230 }
231
232 // If there are no entries, return "empty" lists
233 if ((rsc_names != NULL) && (*rsc_names == NULL)) {
234 *rsc_names = g_string_new(" ");
235 }
236 if ((node_names != NULL) && (*node_names == NULL)) {
237 *node_names = g_string_new(" ");
238 }
239
240 return list;
241}
242
251static void
252copy_meta_to_notify(gpointer key, gpointer value, gpointer user_data)
253{
254 pcmk_action_t *notify = (pcmk_action_t *) user_data;
255
256 /* Any existing meta-attributes (for example, the action timeout) are for
257 * the notify action itself, so don't override those.
258 */
259 if (g_hash_table_lookup(notify->meta, (const char *) key) != NULL) {
260 return;
261 }
262
263 pcmk__insert_dup(notify->meta, (const char *) key, (const char *) value);
264}
265
266static void
267add_notify_data_to_action_meta(const notify_data_t *n_data,
269{
270 for (const GSList *item = n_data->keys; item; item = item->next) {
271 const pcmk_nvpair_t *nvpair = (const pcmk_nvpair_t *) item->data;
272
273 pcmk__insert_meta(action, nvpair->name, nvpair->value);
274 }
275}
276
288static pcmk_action_t *
289new_notify_pseudo_action(pcmk_resource_t *rsc, const pcmk_action_t *action,
290 const char *notif_action, const char *notif_type)
291{
292 pcmk_action_t *notify = NULL;
293
294 notify = custom_action(rsc,
295 pcmk__notify_key(rsc->id, notif_type, action->task),
296 notif_action, NULL,
298 rsc->priv->scheduler);
300 pcmk__insert_meta(notify, "notify_key_type", notif_type);
301 pcmk__insert_meta(notify, "notify_key_operation", action->task);
302 return notify;
303}
304
317static pcmk_action_t *
318new_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
319 pcmk_action_t *op, pcmk_action_t *notify_done,
320 const notify_data_t *n_data)
321{
322 char *key = NULL;
323 pcmk_action_t *notify_action = NULL;
324 const char *value = NULL;
325 const char *task = NULL;
326 const char *skip_reason = NULL;
327
328 CRM_CHECK((rsc != NULL) && (node != NULL), return NULL);
329
330 // Ensure we have all the info we need
331 if (op == NULL) {
332 skip_reason = "no action";
333 } else if (notify_done == NULL) {
334 skip_reason = "no parent notification";
335 } else if (!node->details->online) {
336 skip_reason = "node offline";
337 } else if (!pcmk_is_set(op->flags, pcmk__action_runnable)) {
338 skip_reason = "original action not runnable";
339 }
340 if (skip_reason != NULL) {
341 pcmk__rsc_trace(rsc, "Skipping notify action for %s on %s: %s",
342 rsc->id, pcmk__node_name(node), skip_reason);
343 return NULL;
344 }
345
346 value = g_hash_table_lookup(op->meta, "notify_type"); // "pre" or "post"
347 task = g_hash_table_lookup(op->meta, "notify_operation"); // original action
348
349 pcmk__rsc_trace(rsc, "Creating notify action for %s on %s (%s-%s)",
350 rsc->id, pcmk__node_name(node), value, task);
351
352 // Create the notify action
353 key = pcmk__notify_key(rsc->id, value, task);
354 notify_action = custom_action(rsc, key, op->task, node,
356 rsc->priv->scheduler);
357
358 // Add meta-data to notify action
359 g_hash_table_foreach(op->meta, copy_meta_to_notify, notify_action);
360 add_notify_data_to_action_meta(n_data, notify_action);
361
362 // Order notify after original action and before parent notification
363 order_actions(op, notify_action, pcmk__ar_ordered);
364 order_actions(notify_action, notify_done, pcmk__ar_ordered);
365 return notify_action;
366}
367
376static void
377new_post_notify_action(pcmk_resource_t *rsc, const pcmk_node_t *node,
378 notify_data_t *n_data)
379{
380 pcmk_action_t *notify = NULL;
381
382 pcmk__assert(n_data != NULL);
383
384 // Create the "post-" notify action for specified instance
385 notify = new_notify_action(rsc, node, n_data->post, n_data->post_done,
386 n_data);
387 if (notify != NULL) {
389 }
390
391 // Order recurring monitors after all "post-" notifications complete
392 if (n_data->post_done == NULL) {
393 return;
394 }
395 for (GList *iter = rsc->priv->actions; iter != NULL; iter = iter->next) {
396 pcmk_action_t *mon = (pcmk_action_t *) iter->data;
397 const char *interval_ms_s = NULL;
398
399 interval_ms_s = g_hash_table_lookup(mon->meta, PCMK_META_INTERVAL);
400 if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)
401 || pcmk__str_eq(mon->task, PCMK_ACTION_CANCEL, pcmk__str_none)) {
402 continue; // Not a recurring monitor
403 }
405 }
406}
407
442{
443 notify_data_t *n_data = NULL;
444
445 if (!pcmk_is_set(rsc->flags, pcmk__rsc_notify)) {
446 return NULL;
447 }
448
449 n_data = pcmk__assert_alloc(1, sizeof(notify_data_t));
450
451 n_data->action = task;
452
453 if (action != NULL) { // Need "pre-" pseudo-actions
454
455 // Create "pre-" notify pseudo-action for clone
456 n_data->pre = new_notify_pseudo_action(rsc, action, PCMK_ACTION_NOTIFY,
457 "pre");
459 pcmk__insert_meta(n_data->pre, "notify_type", "pre");
460 pcmk__insert_meta(n_data->pre, "notify_operation", n_data->action);
461
462 // Create "pre-" notifications complete pseudo-action for clone
463 n_data->pre_done = new_notify_pseudo_action(rsc, action,
465 "confirmed-pre");
467 pcmk__insert_meta(n_data->pre_done, "notify_type", "pre");
468 pcmk__insert_meta(n_data->pre_done, "notify_operation", n_data->action);
469
470 // Order "pre-" -> "pre-" complete -> original action
471 order_actions(n_data->pre, n_data->pre_done, pcmk__ar_ordered);
473 }
474
475 if (complete != NULL) { // Need "post-" pseudo-actions
476
477 // Create "post-" notify pseudo-action for clone
478 n_data->post = new_notify_pseudo_action(rsc, complete,
479 PCMK_ACTION_NOTIFY, "post");
481 if (pcmk_is_set(complete->flags, pcmk__action_runnable)) {
483 } else {
485 }
486 pcmk__insert_meta(n_data->post, "notify_type", "post");
487 pcmk__insert_meta(n_data->post, "notify_operation", n_data->action);
488
489 // Create "post-" notifications complete pseudo-action for clone
490 n_data->post_done = new_notify_pseudo_action(rsc, complete,
492 "confirmed-post");
494 if (pcmk_is_set(complete->flags, pcmk__action_runnable)) {
496 } else {
498 }
499 pcmk__insert_meta(n_data->post_done, "notify_type", "post");
501 "notify_operation", n_data->action);
502
503 /* Order original action complete -> "post-" -> "post-" complete
504 *
505 * @TODO Should we add |pcmk__ar_unrunnable_first_blocks to these?
506 * Otherwise we might get an invalid transition due to unresolved
507 * dependencies when "complete" is a fencing op (which can happen at
508 * least for bundles) but that op is unrunnable (due to lack of quorum,
509 * for example).
510 */
512 order_actions(n_data->post, n_data->post_done,
514 }
515
516 // If we created both, order "pre-" complete -> "post-"
517 if ((action != NULL) && (complete != NULL)) {
518 order_actions(n_data->pre_done, n_data->post, pcmk__ar_ordered);
519 }
520 return n_data;
521}
522
533static notify_entry_t *
534new_notify_entry(const pcmk_resource_t *rsc, const pcmk_node_t *node)
535{
537
538 entry->rsc = rsc;
539 entry->node = node;
540 return entry;
541}
542
551static void
552collect_resource_data(pcmk_resource_t *rsc, bool activity,
553 notify_data_t *n_data)
554{
555 const GList *iter = NULL;
556 notify_entry_t *entry = NULL;
557 const pcmk_node_t *node = NULL;
558
559 if (n_data == NULL) {
560 return;
561 }
562
563 if (n_data->allowed_nodes == NULL) {
564 n_data->allowed_nodes = rsc->priv->allowed_nodes;
565 }
566
567 // If this is a clone, call recursively for each instance
568 if (rsc->priv->children != NULL) {
569 for (iter = rsc->priv->children; iter != NULL; iter = iter->next) {
570 pcmk_resource_t *child = iter->data;
571
572 collect_resource_data(child, activity, n_data);
573 }
574 return;
575 }
576
577 // This is a notification for a single clone instance
578
579 if (rsc->priv->active_nodes != NULL) {
580 node = rsc->priv->active_nodes->data; // First is sufficient
581 }
582 entry = new_notify_entry(rsc, node);
583
584 // Add notification indicating the resource state
585 switch (rsc->priv->orig_role) {
587 n_data->inactive = g_list_prepend(n_data->inactive, entry);
588 break;
589
591 n_data->active = g_list_prepend(n_data->active, entry);
592 break;
593
595 n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
596 n_data->active = g_list_prepend(n_data->active,
597 dup_notify_entry(entry));
598 break;
599
601 n_data->promoted = g_list_prepend(n_data->promoted, entry);
602 n_data->active = g_list_prepend(n_data->active,
603 dup_notify_entry(entry));
604 break;
605
606 default:
608 "Resource %s role on %s (%s) is not supported for "
609 "notifications (bug?)",
610 rsc->id, pcmk__node_name(node),
612 free(entry);
613 break;
614 }
615
616 if (!activity) {
617 return;
618 }
619
620 // Add notification entries for each of the resource's actions
621 for (iter = rsc->priv->actions; iter != NULL; iter = iter->next) {
622 const pcmk_action_t *op = (const pcmk_action_t *) iter->data;
623
625 && (op->node != NULL)) {
627
628 if ((task == pcmk__action_stop) && op->node->details->unclean) {
629 // Create anyway (additional noise if node can't be fenced)
630 } else if (!pcmk_is_set(op->flags, pcmk__action_runnable)) {
631 continue;
632 }
633
634 entry = new_notify_entry(rsc, op->node);
635
636 switch (task) {
638 n_data->start = g_list_prepend(n_data->start, entry);
639 break;
641 n_data->stop = g_list_prepend(n_data->stop, entry);
642 break;
644 n_data->promote = g_list_prepend(n_data->promote, entry);
645 break;
647 n_data->demote = g_list_prepend(n_data->demote, entry);
648 break;
649 default:
650 free(entry);
651 break;
652 }
653 }
654 }
655}
656
657// For (char *) value
658#define add_notify_env(n_data, key, value) do { \
659 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
660 } while (0)
661
662// For (GString *) value
663#define add_notify_env_gs(n_data, key, value) do { \
664 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
665 (const char *) value->str); \
666 } while (0)
667
668// For (GString *) value
669#define add_notify_env_free_gs(n_data, key, value) do { \
670 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
671 (const char *) value->str); \
672 g_string_free(value, TRUE); value = NULL; \
673 } while (0)
674
682static void
683add_notif_keys(const pcmk_resource_t *rsc, notify_data_t *n_data)
684{
685 bool required = false; // Whether to make notify actions required
686 GString *rsc_list = NULL;
687 GString *node_list = NULL;
688 GString *metal_list = NULL;
689 const char *source = NULL;
690 GList *nodes = NULL;
691
692 n_data->stop = notify_entries_to_strings(n_data->stop,
693 &rsc_list, &node_list);
694 if ((strcmp(" ", (const char *) rsc_list->str) != 0)
695 && pcmk__str_eq(n_data->action, PCMK_ACTION_STOP, pcmk__str_none)) {
696 required = true;
697 }
698 add_notify_env_free_gs(n_data, "notify_stop_resource", rsc_list);
699 add_notify_env_free_gs(n_data, "notify_stop_uname", node_list);
700
701 if ((n_data->start != NULL)
702 && pcmk__str_eq(n_data->action, PCMK_ACTION_START, pcmk__str_none)) {
703 required = true;
704 }
705 n_data->start = notify_entries_to_strings(n_data->start,
706 &rsc_list, &node_list);
707 add_notify_env_free_gs(n_data, "notify_start_resource", rsc_list);
708 add_notify_env_free_gs(n_data, "notify_start_uname", node_list);
709
710 if ((n_data->demote != NULL)
711 && pcmk__str_eq(n_data->action, PCMK_ACTION_DEMOTE, pcmk__str_none)) {
712 required = true;
713 }
714 n_data->demote = notify_entries_to_strings(n_data->demote,
715 &rsc_list, &node_list);
716 add_notify_env_free_gs(n_data, "notify_demote_resource", rsc_list);
717 add_notify_env_free_gs(n_data, "notify_demote_uname", node_list);
718
719 if ((n_data->promote != NULL)
720 && pcmk__str_eq(n_data->action, PCMK_ACTION_PROMOTE, pcmk__str_none)) {
721 required = true;
722 }
723 n_data->promote = notify_entries_to_strings(n_data->promote,
724 &rsc_list, &node_list);
725 add_notify_env_free_gs(n_data, "notify_promote_resource", rsc_list);
726 add_notify_env_free_gs(n_data, "notify_promote_uname", node_list);
727
728 n_data->active = notify_entries_to_strings(n_data->active,
729 &rsc_list, &node_list);
730 add_notify_env_free_gs(n_data, "notify_active_resource", rsc_list);
731 add_notify_env_free_gs(n_data, "notify_active_uname", node_list);
732
733 n_data->unpromoted = notify_entries_to_strings(n_data->unpromoted,
734 &rsc_list, &node_list);
735 add_notify_env_gs(n_data, "notify_unpromoted_resource", rsc_list);
736 add_notify_env_gs(n_data, "notify_unpromoted_uname", node_list);
737
738 // Deprecated: kept for backward compatibility with older resource agents
739 add_notify_env_free_gs(n_data, "notify_slave_resource", rsc_list);
740 add_notify_env_free_gs(n_data, "notify_slave_uname", node_list);
741
742 n_data->promoted = notify_entries_to_strings(n_data->promoted,
743 &rsc_list, &node_list);
744 add_notify_env_gs(n_data, "notify_promoted_resource", rsc_list);
745 add_notify_env_gs(n_data, "notify_promoted_uname", node_list);
746
747 // Deprecated: kept for backward compatibility with older resource agents
748 add_notify_env_free_gs(n_data, "notify_master_resource", rsc_list);
749 add_notify_env_free_gs(n_data, "notify_master_uname", node_list);
750
751 n_data->inactive = notify_entries_to_strings(n_data->inactive,
752 &rsc_list, NULL);
753 add_notify_env_free_gs(n_data, "notify_inactive_resource", rsc_list);
754
755 nodes = g_hash_table_get_values(n_data->allowed_nodes);
756 if (!pcmk__is_daemon) {
757 /* For display purposes, sort the node list, for consistent
758 * regression test output (while avoiding the performance hit
759 * for the live cluster).
760 */
761 nodes = g_list_sort(nodes, pe__cmp_node_name);
762 }
763 get_node_names(nodes, &node_list, NULL);
764 add_notify_env_free_gs(n_data, "notify_available_uname", node_list);
765 g_list_free(nodes);
766
767 source = g_hash_table_lookup(rsc->priv->meta,
769 if (pcmk__str_eq(PCMK_VALUE_HOST, source, pcmk__str_none)) {
770 get_node_names(rsc->priv->scheduler->nodes, &node_list, &metal_list);
771 add_notify_env_free_gs(n_data, "notify_all_hosts", metal_list);
772 } else {
773 get_node_names(rsc->priv->scheduler->nodes, &node_list, NULL);
774 }
775 add_notify_env_free_gs(n_data, "notify_all_uname", node_list);
776
777 if (required && (n_data->pre != NULL)) {
780 }
781
782 if (required && (n_data->post != NULL)) {
785 }
786}
787
788/*
789 * \internal
790 * \brief Find any remote connection start relevant to an action
791 *
792 * \param[in] action Action to check
793 *
794 * \return If action is behind a remote connection, connection's start
795 */
796static pcmk_action_t *
797find_remote_start(pcmk_action_t *action)
798{
799 if ((action != NULL) && (action->node != NULL)) {
800 pcmk_resource_t *remote_rsc = action->node->priv->remote;
801
802 if (remote_rsc != NULL) {
803 return find_first_action(remote_rsc->priv->actions, NULL,
805 NULL);
806 }
807 }
808 return NULL;
809}
810
818static void
819create_notify_actions(pcmk_resource_t *rsc, notify_data_t *n_data)
820{
821 GList *iter = NULL;
822 pcmk_action_t *stop = NULL;
823 pcmk_action_t *start = NULL;
824 enum pcmk__action_type task = pcmk__parse_action(n_data->action);
825
826 // If this is a clone, call recursively for each instance
827 if (rsc->priv->children != NULL) {
828 g_list_foreach(rsc->priv->children, (GFunc) create_notify_actions,
829 n_data);
830 return;
831 }
832
833 // Add notification meta-attributes to original actions
834 for (iter = rsc->priv->actions; iter != NULL; iter = iter->next) {
835 pcmk_action_t *op = (pcmk_action_t *) iter->data;
836
838 && (op->node != NULL)) {
839 switch (pcmk__parse_action(op->task)) {
844 add_notify_data_to_action_meta(n_data, op);
845 break;
846 default:
847 break;
848 }
849 }
850 }
851
852 // Skip notify action itself if original action was not needed
853 switch (task) {
855 if (n_data->start == NULL) {
856 pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
857 rsc->id, n_data->action);
858 return;
859 }
860 break;
861
863 if (n_data->promote == NULL) {
864 pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
865 rsc->id, n_data->action);
866 return;
867 }
868 break;
869
871 if (n_data->demote == NULL) {
872 pcmk__rsc_trace(rsc, "No notify action needed for %s %s",
873 rsc->id, n_data->action);
874 return;
875 }
876 break;
877
878 default:
879 // We cannot do same for stop because it might be implied by fencing
880 break;
881 }
882
883 pcmk__rsc_trace(rsc, "Creating notify actions for %s %s",
884 rsc->id, n_data->action);
885
886 // Create notify actions for stop or demote
887 if ((rsc->priv->orig_role != pcmk_role_stopped)
888 && ((task == pcmk__action_stop) || (task == pcmk__action_demote))) {
889
891 NULL);
892
893 for (iter = rsc->priv->active_nodes;
894 iter != NULL; iter = iter->next) {
895
896 pcmk_node_t *current_node = (pcmk_node_t *) iter->data;
897
898 /* If a stop is a pseudo-action implied by fencing, don't try to
899 * notify the node getting fenced.
900 */
901 if ((stop != NULL)
903 && (current_node->details->unclean
904 || pcmk_is_set(current_node->priv->flags,
906 continue;
907 }
908
909 new_notify_action(rsc, current_node, n_data->pre,
910 n_data->pre_done, n_data);
911
912 if ((task == pcmk__action_demote) || (stop == NULL)
914 new_post_notify_action(rsc, current_node, n_data);
915 }
916 }
917 }
918
919 // Create notify actions for start or promote
920 if ((rsc->priv->next_role != pcmk_role_stopped)
921 && ((task == pcmk__action_start) || (task == pcmk__action_promote))) {
922
923 start = find_first_action(rsc->priv->actions, NULL,
924 PCMK_ACTION_START, NULL);
925 if (start != NULL) {
926 pcmk_action_t *remote_start = find_remote_start(start);
927
928 if ((remote_start != NULL)
929 && !pcmk_is_set(remote_start->flags, pcmk__action_runnable)) {
930 /* Start and promote actions for a clone instance behind
931 * a Pacemaker Remote connection happen after the
932 * connection starts. If the connection start is blocked, do
933 * not schedule notifications for these actions.
934 */
935 return;
936 }
937 }
938 if (rsc->priv->assigned_node == NULL) {
940 "Next role '%s' but %s is not allocated",
941 pcmk_role_text(rsc->priv->next_role), rsc->id);
942 return;
943 }
944 if ((task != pcmk__action_start) || (start == NULL)
946
947 new_notify_action(rsc, rsc->priv->assigned_node, n_data->pre,
948 n_data->pre_done, n_data);
949 }
950 new_post_notify_action(rsc, rsc->priv->assigned_node, n_data);
951 }
952}
953
961void
963{
964 if ((rsc == NULL) || (n_data == NULL)) {
965 return;
966 }
967 collect_resource_data(rsc, true, n_data);
968 add_notif_keys(rsc, n_data);
969 create_notify_actions(rsc, n_data);
970}
971
978void
980{
981 if (n_data == NULL) {
982 return;
983 }
984 g_list_free_full(n_data->stop, free);
985 g_list_free_full(n_data->start, free);
986 g_list_free_full(n_data->demote, free);
987 g_list_free_full(n_data->promote, free);
988 g_list_free_full(n_data->promoted, free);
989 g_list_free_full(n_data->unpromoted, free);
990 g_list_free_full(n_data->active, free);
991 g_list_free_full(n_data->inactive, free);
992 pcmk_free_nvpairs(n_data->keys);
993 free(n_data);
994}
995
1010void
1012 pcmk_action_t *stonith_op)
1013{
1014 notify_data_t *n_data;
1015
1016 crm_info("Ordering notifications for implied %s after fencing", stop->uuid);
1018 stonith_op);
1019
1020 if (n_data != NULL) {
1021 collect_resource_data(rsc, false, n_data);
1022 add_notify_env(n_data, "notify_stop_resource", rsc->id);
1023 add_notify_env(n_data, "notify_stop_uname", stop->node->priv->name);
1024 create_notify_actions(uber_parent(rsc), n_data);
1026 }
1027}
@ pcmk__ar_first_implies_then
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
#define PCMK_ACTION_STOP
Definition actions.h:66
#define PCMK_ACTION_CANCEL
Definition actions.h:36
#define PCMK_ACTION_PROMOTE
Definition actions.h:57
#define PCMK_ACTION_START
Definition actions.h:63
#define PCMK_ACTION_NOTIFIED
Definition actions.h:52
#define PCMK_ACTION_DEMOTE
Definition actions.h:40
#define PCMK_ACTION_NOTIFY
Definition actions.h:53
@ pcmk__action_runnable
@ pcmk__action_optional
@ pcmk__action_pseudo
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition actions.c:365
#define pcmk__set_action_flags(action, flags_to_set)
#define pcmk__clear_action_flags(action, flags_to_clear)
enum pcmk__action_type pcmk__parse_action(const char *action_name)
Definition actions.c:90
pcmk__action_type
@ pcmk__action_stop
@ pcmk__action_start
@ pcmk__action_demote
@ pcmk__action_promote
bool pcmk__is_daemon
Definition logging.c:47
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:246
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition complex.c:999
#define crm_info(fmt, args...)
Definition logging.h:365
#define CRM_LOG_ASSERT(expr)
Definition logging.h:196
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
@ pcmk__node_remote_reset
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition nvpair.c:103
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_INTERVAL
Definition options.h:92
#define PCMK_META_CONTAINER_ATTRIBUTE_TARGET
Definition options.h:86
#define PCMK_VALUE_HOST
Definition options.h:162
const char * action
Definition pcmk_fence.c:32
#define add_notify_env(n_data, key, value)
Definition pe_notif.c:658
#define add_notify_env_free_gs(n_data, key, value)
Definition pe_notif.c:669
#define add_notify_env_gs(n_data, key, value)
Definition pe_notif.c:663
void pe__free_action_notification_data(notify_data_t *n_data)
Definition pe_notif.c:979
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:440
void pe__order_notifs_after_fencing(const pcmk_action_t *stop, pcmk_resource_t *rsc, pcmk_action_t *stonith_op)
Definition pe_notif.c:1011
struct notify_entry_s notify_entry_t
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition pe_notif.c:962
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
Definition utils.c:483
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:182
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
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.
@ pcmk__rsc_notify
#define pcmk__assert(expr)
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition roles.c:23
@ pcmk_role_started
Started.
Definition roles.h:37
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:38
@ pcmk_role_promoted
Promoted.
Definition roles.h:39
@ pcmk_role_stopped
Stopped.
Definition roles.h:36
#define pcmk__sched_err(scheduler, fmt...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:26
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:703
@ pcmk__str_none
@ pcmk__str_null_matches
pcmk_action_t * pre
const char * action
GHashTable * allowed_nodes
pcmk_action_t * post
pcmk_action_t * pre_done
pcmk_action_t * post_done
pcmk_node_t * node
GHashTable * meta
gboolean online
Definition nodes.h:50
gboolean unclean
Definition nodes.h:58
pcmk_scheduler_t * scheduler
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
GList * nodes
Definition scheduler.h:97
pcmk__node_private_t * priv
Definition nodes.h:85
struct pcmk__node_details * details
Definition nodes.h:82
Wrappers for and extensions to libxml2.