pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
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
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 names
83 return strcmp(entry_a->node->details->id, entry_b->node->details->id);
84}
85
95static notify_entry_t *
96dup_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
119static void
120get_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
177static GList *
178notify_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
244static void
245copy_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
260static void
261add_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
282static pcmk_action_t *
283new_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
311static pcmk_action_t *
312new_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
370static void
371new_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
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");
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");
498 "notify_operation", n_data->action);
499
500 // Order original action complete -> "post-" -> "post-" complete
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
523static notify_entry_t *
524new_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
542static void
543collect_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) {
578 n_data->inactive = g_list_prepend(n_data->inactive, entry);
579 break;
580
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
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) {
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;
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
671static void
672add_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 */
784static pcmk_action_t *
785find_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
806static void
807create_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)) {
828 case pcmk_action_stop:
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) {
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
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
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)
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
942void
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
959void
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
991void
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);
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}
@ 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:74
#define PCMK_ACTION_CANCEL
Definition actions.h:45
#define PCMK_ACTION_PROMOTE
Definition actions.h:65
#define PCMK_ACTION_START
Definition actions.h:71
#define PCMK_ACTION_NOTIFIED
Definition actions.h:60
@ pcmk_action_runnable
Whether action is runnable.
Definition actions.h:241
@ pcmk_action_pseudo
Whether action does not require invoking an agent.
Definition actions.h:238
@ pcmk_action_optional
Whether action should not be executed.
Definition actions.h:244
action_tasks
Possible actions (including some pseudo-actions)
Definition actions.h:79
@ pcmk_action_start
Start.
Definition actions.h:88
@ pcmk_action_demote
Demote.
Definition actions.h:97
@ pcmk_action_promote
Promote.
Definition actions.h:94
@ pcmk_action_stop
Stop.
Definition actions.h:85
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
#define PCMK_ACTION_NOTIFY
Definition actions.h:61
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition actions.c:183
bool pcmk__is_daemon
Definition logging.c:47
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:99
enum action_tasks text2task(const char *task)
Definition common.c:360
const char * role2text(enum rsc_role_e role)
Definition common.c:458
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition complex.c:936
#define INFINITY
Definition crm.h:98
#define crm_info(fmt, args...)
Definition logging.h:382
#define CRM_LOG_ASSERT(expr)
Definition logging.h:222
#define CRM_CHECK(expr, failure_action)
Definition logging.h:238
#define crm_err(fmt, args...)
Definition logging.h:379
#define XML_RSC_ATTR_TARGET
Definition msg_xml.h:242
#define XML_LRM_ATTR_INTERVAL_MS
Definition msg_xml.h:304
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition nvpair.c:102
const char * action
Definition pcmk_fence.c:30
#define add_notify_env(n_data, key, value)
Definition pe_notif.c:647
#define add_notify_env_free_gs(n_data, key, value)
Definition pe_notif.c:658
#define add_notify_env_gs(n_data, key, value)
Definition pe_notif.c:652
void pe__free_action_notification_data(notify_data_t *n_data)
Definition pe_notif.c:960
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
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
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:943
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition utils.c:450
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:146
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:37
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.
#define pe_proc_err(fmt...)
Definition internal.h:49
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:85
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:76
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:508
bool pe__is_guest_node(const pcmk_node_t *node)
Definition remote.c:33
@ pcmk_rsc_notify
Whether resource has clone notifications enabled.
Definition resources.h:115
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_role_started
Started.
Definition roles.h:30
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:31
@ pcmk_role_promoted
Promoted.
Definition roles.h:32
@ pcmk_role_stopped
Stopped.
Definition roles.h:29
@ 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
Implementation of pcmk_action_t.
Definition actions.h:390
pcmk_node_t * node
Node to execute action on, if any.
Definition actions.h:401
char * uuid
Action key.
Definition actions.h:404
char * task
Action name.
Definition actions.h:403
int priority
Definition actions.h:398
GHashTable * meta
Meta-attributes relevant to action.
Definition actions.h:414
enum pe_action_flags flags
Group of enum pe_action_flags.
Definition actions.h:409
Implementation of pcmk_node_t.
Definition nodes.h:130
struct pe_node_shared_s * details
Basic node information.
Definition nodes.h:134
gboolean online
Whether online.
Definition nodes.h:72
const char * uname
Node name in cluster.
Definition nodes.h:68
gboolean unclean
Whether node requires fencing.
Definition nodes.h:76
Implementation of pcmk_resource_t.
Definition resources.h:399
GList * running_on
Nodes where resource may be active.
Definition resources.h:460
GList * actions
Definition resources.h:447
GHashTable * meta
Resource's meta-attributes.
Definition resources.h:471
GList * children
Resource's child resources, if any.
Definition resources.h:475
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition resources.h:412
char * id
Resource ID in configuration.
Definition resources.h:400
pcmk_node_t * allocated_to
Node resource is assigned to.
Definition resources.h:451
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition resources.h:466
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition resources.h:429
enum rsc_role_e next_role
Resource's scheduled next role.
Definition resources.h:469
enum rsc_role_e role
Resource's current role.
Definition resources.h:468
GList * nodes
Nodes in cluster.
Definition scheduler.h:195