pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pe_notif.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 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#include <pacemaker-internal.h>
13
14typedef struct notify_entry_s {
15 pe_resource_t *rsc;
16 pe_node_t *node;
18
32static gint
33compare_notify_entries(gconstpointer a, gconstpointer b)
34{
35 int tmp;
36 const notify_entry_t *entry_a = a;
37 const notify_entry_t *entry_b = b;
38
39 // NULL a or b is not actually possible
40 if ((entry_a == NULL) && (entry_b == NULL)) {
41 return 0;
42 }
43 if (entry_a == NULL) {
44 return 1;
45 }
46 if (entry_b == NULL) {
47 return -1;
48 }
49
50 // NULL resources sort first
51 if ((entry_a->rsc == NULL) && (entry_b->rsc == NULL)) {
52 return 0;
53 }
54 if (entry_a->rsc == NULL) {
55 return 1;
56 }
57 if (entry_b->rsc == NULL) {
58 return -1;
59 }
60
61 // Compare resource names
62 tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
63 if (tmp != 0) {
64 return tmp;
65 }
66
67 // Otherwise NULL nodes sort first
68 if ((entry_a->node == NULL) && (entry_b->node == NULL)) {
69 return 0;
70 }
71 if (entry_a->node == NULL) {
72 return 1;
73 }
74 if (entry_b->node == NULL) {
75 return -1;
76 }
77
78 // Finally, compare node names
79 return strcmp(entry_a->node->details->id, entry_b->node->details->id);
80}
81
91static notify_entry_t *
92dup_notify_entry(notify_entry_t *entry)
93{
94 notify_entry_t *dup = calloc(1, sizeof(notify_entry_t));
95
96 CRM_ASSERT(dup != NULL);
97 dup->rsc = entry->rsc;
98 dup->node = entry->node;
99 return dup;
100}
101
115static void
116get_node_names(GList *list, GString **all_node_names, GString **host_node_names)
117{
118 if (all_node_names != NULL) {
119 *all_node_names = NULL;
120 }
121 if (host_node_names != NULL) {
122 *host_node_names = NULL;
123 }
124
125 for (GList *iter = list; iter != NULL; iter = iter->next) {
126 pe_node_t *node = (pe_node_t *) iter->data;
127
128 if (node->details->uname == NULL) {
129 continue;
130 }
131
132 // Always add to list of all node names
133 if (all_node_names != NULL) {
134 pcmk__add_word(all_node_names, 1024, node->details->uname);
135 }
136
137 // Add to host node name list if appropriate
138 if (host_node_names != NULL) {
139 if (pe__is_guest_node(node)
140 && (node->details->remote_rsc->container->running_on != NULL)) {
141 node = pe__current_node(node->details->remote_rsc->container);
142 if (node->details->uname == NULL) {
143 continue;
144 }
145 }
146 pcmk__add_word(host_node_names, 1024, node->details->uname);
147 }
148 }
149
150 if ((all_node_names != NULL) && (*all_node_names == NULL)) {
151 *all_node_names = g_string_new(" ");
152 }
153 if ((host_node_names != NULL) && (*host_node_names == NULL)) {
154 *host_node_names = g_string_new(" ");
155 }
156}
157
172static GList *
173notify_entries_to_strings(GList *list, GString **rsc_names,
174 GString **node_names)
175{
176 const char *last_rsc_id = NULL;
177
178 // Initialize output lists to NULL
179 if (rsc_names != NULL) {
180 *rsc_names = NULL;
181 }
182 if (node_names != NULL) {
183 *node_names = NULL;
184 }
185
186 // Sort input list for user-friendliness (and ease of filtering duplicates)
187 list = g_list_sort(list, compare_notify_entries);
188
189 for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
190 notify_entry_t *entry = (notify_entry_t *) gIter->data;
191
192 // Entry must have a resource (with ID)
193 CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
194 && (entry->rsc->id != NULL));
195 if ((entry == NULL) || (entry->rsc == NULL)
196 || (entry->rsc->id == NULL)) {
197 continue;
198 }
199
200 // Entry must have a node unless listing inactive resources
201 CRM_LOG_ASSERT((node_names == NULL) || (entry->node != NULL));
202 if ((node_names != NULL) && (entry->node == NULL)) {
203 continue;
204 }
205
206 // Don't add duplicates of a particular clone instance
207 if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
208 continue;
209 }
210 last_rsc_id = entry->rsc->id;
211
212 if (rsc_names != NULL) {
213 pcmk__add_word(rsc_names, 1024, entry->rsc->id);
214 }
215 if ((node_names != NULL) && (entry->node->details->uname != NULL)) {
216 pcmk__add_word(node_names, 1024, entry->node->details->uname);
217 }
218 }
219
220 // If there are no entries, return "empty" lists
221 if ((rsc_names != NULL) && (*rsc_names == NULL)) {
222 *rsc_names = g_string_new(" ");
223 }
224 if ((node_names != NULL) && (*node_names == NULL)) {
225 *node_names = g_string_new(" ");
226 }
227
228 return list;
229}
230
239static void
240copy_meta_to_notify(gpointer key, gpointer value, gpointer user_data)
241{
242 pe_action_t *notify = (pe_action_t *) user_data;
243
244 /* Any existing meta-attributes (for example, the action timeout) are for
245 * the notify action itself, so don't override those.
246 */
247 if (g_hash_table_lookup(notify->meta, (const char *) key) != NULL) {
248 return;
249 }
250
251 g_hash_table_insert(notify->meta, strdup((const char *) key),
252 strdup((const char *) value));
253}
254
255static void
256add_notify_data_to_action_meta(notify_data_t *n_data, pe_action_t *action)
257{
258 for (GSList *item = n_data->keys; item; item = item->next) {
259 pcmk_nvpair_t *nvpair = item->data;
260
261 add_hash_param(action->meta, nvpair->name, nvpair->value);
262 }
263}
264
276static pe_action_t *
277new_notify_pseudo_action(pe_resource_t *rsc, const pe_action_t *action,
278 const char *notif_action, const char *notif_type)
279{
280 pe_action_t *notify = NULL;
281
282 notify = custom_action(rsc,
283 pcmk__notify_key(rsc->id, notif_type, action->task),
284 notif_action, NULL,
286 TRUE, rsc->cluster);
288 add_hash_param(notify->meta, "notify_key_type", notif_type);
289 add_hash_param(notify->meta, "notify_key_operation", action->task);
290 return notify;
291}
292
305static pe_action_t *
306new_notify_action(pe_resource_t *rsc, pe_node_t *node, pe_action_t *op,
307 pe_action_t *notify_done, notify_data_t *n_data)
308{
309 char *key = NULL;
310 pe_action_t *notify_action = NULL;
311 const char *value = NULL;
312 const char *task = NULL;
313 const char *skip_reason = NULL;
314
315 CRM_CHECK((rsc != NULL) && (node != NULL), return NULL);
316
317 // Ensure we have all the info we need
318 if (op == NULL) {
319 skip_reason = "no action";
320 } else if (notify_done == NULL) {
321 skip_reason = "no parent notification";
322 } else if (!node->details->online) {
323 skip_reason = "node offline";
324 } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
325 skip_reason = "original action not runnable";
326 }
327 if (skip_reason != NULL) {
328 pe_rsc_trace(rsc, "Skipping notify action for %s on %s: %s",
329 rsc->id, pe__node_name(node), skip_reason);
330 return NULL;
331 }
332
333 value = g_hash_table_lookup(op->meta, "notify_type"); // "pre" or "post"
334 task = g_hash_table_lookup(op->meta, "notify_operation"); // original action
335
336 pe_rsc_trace(rsc, "Creating notify action for %s on %s (%s-%s)",
337 rsc->id, pe__node_name(node), value, task);
338
339 // Create the notify action
340 key = pcmk__notify_key(rsc->id, value, task);
341 notify_action = custom_action(rsc, key, op->task, node,
343 TRUE, rsc->cluster);
344
345 // Add meta-data to notify action
346 g_hash_table_foreach(op->meta, copy_meta_to_notify, notify_action);
347 add_notify_data_to_action_meta(n_data, notify_action);
348
349 // Order notify after original action and before parent notification
350 order_actions(op, notify_action, pe_order_optional);
351 order_actions(notify_action, notify_done, pe_order_optional);
352 return notify_action;
353}
354
363static void
364new_post_notify_action(pe_resource_t *rsc, pe_node_t *node,
365 notify_data_t *n_data)
366{
367 pe_action_t *notify = NULL;
368
369 CRM_ASSERT(n_data != NULL);
370
371 // Create the "post-" notify action for specified instance
372 notify = new_notify_action(rsc, node, n_data->post, n_data->post_done,
373 n_data);
374 if (notify != NULL) {
375 notify->priority = INFINITY;
376 }
377
378 // Order recurring monitors after all "post-" notifications complete
379 if (n_data->post_done == NULL) {
380 return;
381 }
382 for (GList *iter = rsc->actions; iter != NULL; iter = iter->next) {
383 pe_action_t *mon = (pe_action_t *) iter->data;
384 const char *interval_ms_s = NULL;
385
386 interval_ms_s = g_hash_table_lookup(mon->meta,
388 if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)
389 || pcmk__str_eq(mon->task, RSC_CANCEL, pcmk__str_none)) {
390 continue; // Not a recurring monitor
391 }
393 }
394}
395
429 pe_action_t *action, pe_action_t *complete)
430{
431 notify_data_t *n_data = NULL;
432
433 if (!pcmk_is_set(rsc->flags, pe_rsc_notify)) {
434 return NULL;
435 }
436
437 n_data = calloc(1, sizeof(notify_data_t));
438 CRM_ASSERT(n_data != NULL);
439
440 n_data->action = task;
441
442 if (action != NULL) { // Need "pre-" pseudo-actions
443
444 // Create "pre-" notify pseudo-action for clone
445 n_data->pre = new_notify_pseudo_action(rsc, action, RSC_NOTIFY, "pre");
447 add_hash_param(n_data->pre->meta, "notify_type", "pre");
448 add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
449
450 // Create "pre-" notifications complete pseudo-action for clone
451 n_data->pre_done = new_notify_pseudo_action(rsc, action, RSC_NOTIFIED,
452 "confirmed-pre");
454 add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
456 "notify_operation", n_data->action);
457
458 // Order "pre-" -> "pre-" complete -> original action
459 order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
461 }
462
463 if (complete != NULL) { // Need "post-" pseudo-actions
464
465 // Create "post-" notify pseudo-action for clone
466 n_data->post = new_notify_pseudo_action(rsc, complete, RSC_NOTIFY,
467 "post");
468 n_data->post->priority = INFINITY;
469 if (pcmk_is_set(complete->flags, pe_action_runnable)) {
471 } else {
473 }
474 add_hash_param(n_data->post->meta, "notify_type", "post");
475 add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
476
477 // Create "post-" notifications complete pseudo-action for clone
478 n_data->post_done = new_notify_pseudo_action(rsc, complete,
480 "confirmed-post");
481 n_data->post_done->priority = INFINITY;
482 if (pcmk_is_set(complete->flags, pe_action_runnable)) {
484 } else {
486 }
487 add_hash_param(n_data->post_done->meta, "notify_type", "post");
489 "notify_operation", n_data->action);
490
491 // Order original action complete -> "post-" -> "post-" complete
492 order_actions(complete, n_data->post, pe_order_implies_then);
494 }
495
496 // If we created both, order "pre-" complete -> "post-"
497 if ((action != NULL) && (complete != NULL)) {
498 order_actions(n_data->pre_done, n_data->post, pe_order_optional);
499 }
500 return n_data;
501}
502
513static notify_entry_t *
514new_notify_entry(pe_resource_t *rsc, pe_node_t *node)
515{
516 notify_entry_t *entry = calloc(1, sizeof(notify_entry_t));
517
518 CRM_ASSERT(entry != NULL);
519 entry->rsc = rsc;
520 entry->node = node;
521 return entry;
522}
523
532static void
533collect_resource_data(pe_resource_t *rsc, bool activity, notify_data_t *n_data)
534{
535 GList *iter = NULL;
536 notify_entry_t *entry = NULL;
537 pe_node_t *node = NULL;
538
539 if (n_data == NULL) {
540 return;
541 }
542
543 if (n_data->allowed_nodes == NULL) {
544 n_data->allowed_nodes = rsc->allowed_nodes;
545 }
546
547 // If this is a clone, call recursively for each instance
548 if (rsc->children != NULL) {
549 for (iter = rsc->children; iter != NULL; iter = iter->next) {
550 pe_resource_t *child = (pe_resource_t *) iter->data;
551
552 collect_resource_data(child, activity, n_data);
553 }
554 return;
555 }
556
557 // This is a notification for a single clone instance
558
559 if (rsc->running_on != NULL) {
560 node = rsc->running_on->data; // First is sufficient
561 }
562 entry = new_notify_entry(rsc, node);
563
564 // Add notification indicating the resource state
565 switch (rsc->role) {
566 case RSC_ROLE_STOPPED:
567 n_data->inactive = g_list_prepend(n_data->inactive, entry);
568 break;
569
570 case RSC_ROLE_STARTED:
571 n_data->active = g_list_prepend(n_data->active, entry);
572 break;
573
575 n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
576 n_data->active = g_list_prepend(n_data->active,
577 dup_notify_entry(entry));
578 break;
579
581 n_data->promoted = g_list_prepend(n_data->promoted, entry);
582 n_data->active = g_list_prepend(n_data->active,
583 dup_notify_entry(entry));
584 break;
585
586 default:
587 crm_err("Resource %s role on %s (%s) is not supported for "
588 "notifications (bug?)",
589 rsc->id, pe__node_name(node), role2text(rsc->role));
590 free(entry);
591 break;
592 }
593
594 if (!activity) {
595 return;
596 }
597
598 // Add notification entries for each of the resource's actions
599 for (iter = rsc->actions; iter != NULL; iter = iter->next) {
600 pe_action_t *op = (pe_action_t *) iter->data;
601
602 if (!pcmk_is_set(op->flags, pe_action_optional) && (op->node != NULL)) {
603 enum action_tasks task = text2task(op->task);
604
605 if ((task == stop_rsc) && op->node->details->unclean) {
606 // Create anyway (additional noise if node can't be fenced)
607 } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
608 continue;
609 }
610
611 entry = new_notify_entry(rsc, op->node);
612
613 switch (task) {
614 case start_rsc:
615 n_data->start = g_list_prepend(n_data->start, entry);
616 break;
617 case stop_rsc:
618 n_data->stop = g_list_prepend(n_data->stop, entry);
619 break;
620 case action_promote:
621 n_data->promote = g_list_prepend(n_data->promote, entry);
622 break;
623 case action_demote:
624 n_data->demote = g_list_prepend(n_data->demote, entry);
625 break;
626 default:
627 free(entry);
628 break;
629 }
630 }
631 }
632}
633
634// For (char *) value
635#define add_notify_env(n_data, key, value) do { \
636 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
637 } while (0)
638
639// For (GString *) value
640#define add_notify_env_gs(n_data, key, value) do { \
641 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
642 (const char *) value->str); \
643 } while (0)
644
645// For (GString *) value
646#define add_notify_env_free_gs(n_data, key, value) do { \
647 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, \
648 (const char *) value->str); \
649 g_string_free(value, TRUE); value = NULL; \
650 } while (0)
651
659static void
660add_notif_keys(pe_resource_t *rsc, notify_data_t *n_data)
661{
662 bool required = false; // Whether to make notify actions required
663 GString *rsc_list = NULL;
664 GString *node_list = NULL;
665 GString *metal_list = NULL;
666 const char *source = NULL;
667 GList *nodes = NULL;
668
669 n_data->stop = notify_entries_to_strings(n_data->stop,
670 &rsc_list, &node_list);
671 if ((strcmp(" ", (const char *) rsc_list->str) != 0)
672 && pcmk__str_eq(n_data->action, RSC_STOP, pcmk__str_none)) {
673 required = true;
674 }
675 add_notify_env_free_gs(n_data, "notify_stop_resource", rsc_list);
676 add_notify_env_free_gs(n_data, "notify_stop_uname", node_list);
677
678 if ((n_data->start != NULL)
679 && pcmk__str_eq(n_data->action, RSC_START, pcmk__str_none)) {
680 required = true;
681 }
682 n_data->start = notify_entries_to_strings(n_data->start,
683 &rsc_list, &node_list);
684 add_notify_env_free_gs(n_data, "notify_start_resource", rsc_list);
685 add_notify_env_free_gs(n_data, "notify_start_uname", node_list);
686
687 if ((n_data->demote != NULL)
688 && pcmk__str_eq(n_data->action, RSC_DEMOTE, pcmk__str_none)) {
689 required = true;
690 }
691 n_data->demote = notify_entries_to_strings(n_data->demote,
692 &rsc_list, &node_list);
693 add_notify_env_free_gs(n_data, "notify_demote_resource", rsc_list);
694 add_notify_env_free_gs(n_data, "notify_demote_uname", node_list);
695
696 if ((n_data->promote != NULL)
697 && pcmk__str_eq(n_data->action, RSC_PROMOTE, pcmk__str_none)) {
698 required = true;
699 }
700 n_data->promote = notify_entries_to_strings(n_data->promote,
701 &rsc_list, &node_list);
702 add_notify_env_free_gs(n_data, "notify_promote_resource", rsc_list);
703 add_notify_env_free_gs(n_data, "notify_promote_uname", node_list);
704
705 n_data->active = notify_entries_to_strings(n_data->active,
706 &rsc_list, &node_list);
707 add_notify_env_free_gs(n_data, "notify_active_resource", rsc_list);
708 add_notify_env_free_gs(n_data, "notify_active_uname", node_list);
709
710 n_data->unpromoted = notify_entries_to_strings(n_data->unpromoted,
711 &rsc_list, &node_list);
712 add_notify_env_gs(n_data, "notify_unpromoted_resource", rsc_list);
713 add_notify_env_gs(n_data, "notify_unpromoted_uname", node_list);
714
715 // Deprecated: kept for backward compatibility with older resource agents
716 add_notify_env_free_gs(n_data, "notify_slave_resource", rsc_list);
717 add_notify_env_free_gs(n_data, "notify_slave_uname", node_list);
718
719 n_data->promoted = notify_entries_to_strings(n_data->promoted,
720 &rsc_list, &node_list);
721 add_notify_env_gs(n_data, "notify_promoted_resource", rsc_list);
722 add_notify_env_gs(n_data, "notify_promoted_uname", node_list);
723
724 // Deprecated: kept for backward compatibility with older resource agents
725 add_notify_env_free_gs(n_data, "notify_master_resource", rsc_list);
726 add_notify_env_free_gs(n_data, "notify_master_uname", node_list);
727
728 n_data->inactive = notify_entries_to_strings(n_data->inactive,
729 &rsc_list, NULL);
730 add_notify_env_free_gs(n_data, "notify_inactive_resource", rsc_list);
731
732 nodes = g_hash_table_get_values(n_data->allowed_nodes);
733 if (!pcmk__is_daemon) {
734 /* For display purposes, sort the node list, for consistent
735 * regression test output (while avoiding the performance hit
736 * for the live cluster).
737 */
738 nodes = g_list_sort(nodes, pe__cmp_node_name);
739 }
740 get_node_names(nodes, &node_list, NULL);
741 add_notify_env_free_gs(n_data, "notify_available_uname", node_list);
742 g_list_free(nodes);
743
744 source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
745 if (pcmk__str_eq("host", source, pcmk__str_none)) {
746 get_node_names(rsc->cluster->nodes, &node_list, &metal_list);
747 add_notify_env_free_gs(n_data, "notify_all_hosts", metal_list);
748 } else {
749 get_node_names(rsc->cluster->nodes, &node_list, NULL);
750 }
751 add_notify_env_free_gs(n_data, "notify_all_uname", node_list);
752
753 if (required && (n_data->pre != NULL)) {
756 }
757
758 if (required && (n_data->post != NULL)) {
761 }
762}
763
764/*
765 * \internal
766 * \brief Find any remote connection start relevant to an action
767 *
768 * \param[in] action Action to check
769 *
770 * \return If action is behind a remote connection, connection's start
771 */
772static pe_action_t *
773find_remote_start(pe_action_t *action)
774{
775 if ((action != NULL) && (action->node != NULL)) {
776 pe_resource_t *remote_rsc = action->node->details->remote_rsc;
777
778 if (remote_rsc != NULL) {
779 return find_first_action(remote_rsc->actions, NULL, RSC_START,
780 NULL);
781 }
782 }
783 return NULL;
784}
785
793static void
794create_notify_actions(pe_resource_t *rsc, notify_data_t *n_data)
795{
796 GList *iter = NULL;
797 pe_action_t *stop = NULL;
798 pe_action_t *start = NULL;
799 enum action_tasks task = text2task(n_data->action);
800
801 // If this is a clone, call recursively for each instance
802 if (rsc->children != NULL) {
803 g_list_foreach(rsc->children, (GFunc) create_notify_actions, n_data);
804 return;
805 }
806
807 // Add notification meta-attributes to original actions
808 for (iter = rsc->actions; iter != NULL; iter = iter->next) {
809 pe_action_t *op = (pe_action_t *) iter->data;
810
811 if (!pcmk_is_set(op->flags, pe_action_optional) && (op->node != NULL)) {
812 switch (text2task(op->task)) {
813 case start_rsc:
814 case stop_rsc:
815 case action_promote:
816 case action_demote:
817 add_notify_data_to_action_meta(n_data, op);
818 break;
819 default:
820 break;
821 }
822 }
823 }
824
825 // Skip notify action itself if original action was not needed
826 switch (task) {
827 case start_rsc:
828 if (n_data->start == NULL) {
829 pe_rsc_trace(rsc, "No notify action needed for %s %s",
830 rsc->id, n_data->action);
831 return;
832 }
833 break;
834
835 case action_promote:
836 if (n_data->promote == NULL) {
837 pe_rsc_trace(rsc, "No notify action needed for %s %s",
838 rsc->id, n_data->action);
839 return;
840 }
841 break;
842
843 case action_demote:
844 if (n_data->demote == NULL) {
845 pe_rsc_trace(rsc, "No notify action needed for %s %s",
846 rsc->id, n_data->action);
847 return;
848 }
849 break;
850
851 default:
852 // We cannot do same for stop because it might be implied by fencing
853 break;
854 }
855
856 pe_rsc_trace(rsc, "Creating notify actions for %s %s",
857 rsc->id, n_data->action);
858
859 // Create notify actions for stop or demote
860 if ((rsc->role != RSC_ROLE_STOPPED)
861 && ((task == stop_rsc) || (task == action_demote))) {
862
863 stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
864
865 for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
866 pe_node_t *current_node = (pe_node_t *) iter->data;
867
868 /* If a stop is a pseudo-action implied by fencing, don't try to
869 * notify the node getting fenced.
870 */
871 if ((stop != NULL) && pcmk_is_set(stop->flags, pe_action_pseudo)
872 && (current_node->details->unclean
873 || current_node->details->remote_requires_reset)) {
874 continue;
875 }
876
877 new_notify_action(rsc, current_node, n_data->pre,
878 n_data->pre_done, n_data);
879
880 if ((task == action_demote) || (stop == NULL)
882 new_post_notify_action(rsc, current_node, n_data);
883 }
884 }
885 }
886
887 // Create notify actions for start or promote
888 if ((rsc->next_role != RSC_ROLE_STOPPED)
889 && ((task == start_rsc) || (task == action_promote))) {
890
891 start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
892 if (start != NULL) {
893 pe_action_t *remote_start = find_remote_start(start);
894
895 if ((remote_start != NULL)
896 && !pcmk_is_set(remote_start->flags, pe_action_runnable)) {
897 /* Start and promote actions for a clone instance behind
898 * a Pacemaker Remote connection happen after the
899 * connection starts. If the connection start is blocked, do
900 * not schedule notifications for these actions.
901 */
902 return;
903 }
904 }
905 if (rsc->allocated_to == NULL) {
906 pe_proc_err("Next role '%s' but %s is not allocated",
907 role2text(rsc->next_role), rsc->id);
908 return;
909 }
910 if ((task != start_rsc) || (start == NULL)
912
913 new_notify_action(rsc, rsc->allocated_to, n_data->pre,
914 n_data->pre_done, n_data);
915 }
916 new_post_notify_action(rsc, rsc->allocated_to, n_data);
917 }
918}
919
927void
929{
930 if ((rsc == NULL) || (n_data == NULL)) {
931 return;
932 }
933 collect_resource_data(rsc, true, n_data);
934 add_notif_keys(rsc, n_data);
935 create_notify_actions(rsc, n_data);
936}
937
944void
946{
947 if (n_data == NULL) {
948 return;
949 }
950 g_list_free_full(n_data->stop, free);
951 g_list_free_full(n_data->start, free);
952 g_list_free_full(n_data->demote, free);
953 g_list_free_full(n_data->promote, free);
954 g_list_free_full(n_data->promoted, free);
955 g_list_free_full(n_data->unpromoted, free);
956 g_list_free_full(n_data->active, free);
957 g_list_free_full(n_data->inactive, free);
958 pcmk_free_nvpairs(n_data->keys);
959 free(n_data);
960}
961
976void
978 pe_action_t *stonith_op)
979{
980 notify_data_t *n_data;
981
982 crm_info("Ordering notifications for implied %s after fencing", stop->uuid);
983 n_data = pe__clone_notif_pseudo_ops(rsc, RSC_STOP, NULL, stonith_op);
984
985 if (n_data != NULL) {
986 collect_resource_data(rsc, false, n_data);
987 add_notify_env(n_data, "notify_stop_resource", rsc->id);
988 add_notify_env(n_data, "notify_stop_uname", stop->node->details->uname);
989 create_notify_actions(uber_parent(rsc), n_data);
991 }
992}
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:229
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:121
enum action_tasks text2task(const char *task)
Definition: common.c:353
const char * role2text(enum rsc_role_e role)
Definition: common.c:454
action_tasks
Definition: common.h:61
@ start_rsc
Definition: common.h:66
@ action_demote
Definition: common.h:72
@ stop_rsc
Definition: common.h:64
@ action_promote
Definition: common.h:70
@ RSC_ROLE_STARTED
Definition: common.h:95
@ RSC_ROLE_STOPPED
Definition: common.h:94
@ RSC_ROLE_PROMOTED
Definition: common.h:97
@ RSC_ROLE_UNPROMOTED
Definition: common.h:96
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:912
#define RSC_PROMOTE
Definition: crm.h:205
#define RSC_DEMOTE
Definition: crm.h:207
#define RSC_NOTIFY
Definition: crm.h:210
#define RSC_NOTIFIED
Definition: crm.h:211
#define RSC_START
Definition: crm.h:199
#define INFINITY
Definition: crm.h:99
#define RSC_STOP
Definition: crm.h:202
#define RSC_CANCEL
Definition: crm.h:194
#define crm_info(fmt, args...)
Definition: logging.h:362
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:211
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_err(fmt, args...)
Definition: logging.h:359
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:224
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:298
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
void pe__create_notifications(pe_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:928
#define add_notify_env(n_data, key, value)
Definition: pe_notif.c:635
#define add_notify_env_free_gs(n_data, key, value)
Definition: pe_notif.c:646
#define add_notify_env_gs(n_data, key, value)
Definition: pe_notif.c:640
notify_data_t * pe__clone_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
Definition: pe_notif.c:428
void pe__free_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:945
struct notify_entry_s notify_entry_t
void pe__order_notifs_after_fencing(pe_action_t *stop, pe_resource_t *rsc, pe_action_t *stonith_op)
Definition: pe_notif.c:977
#define pe_rsc_notify
Definition: pe_types.h:261
@ pe_order_implies_then
Definition: pe_types.h:485
@ pe_order_optional
Definition: pe_types.h:481
@ pe_action_optional
Definition: pe_types.h:301
@ pe_action_runnable
Definition: pe_types.h:300
@ pe_action_pseudo
Definition: pe_types.h:299
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, const pe_node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Create or update an action object.
Definition: pe_actions.c:940
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1296
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:180
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:474
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define pe_proc_err(fmt...)
Definition: internal.h:59
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:504
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
#define CRM_ASSERT(expr)
Definition: results.h:42
@ pcmk__str_none
@ pcmk__str_null_matches
const char * action
Definition: internal.h:212
GHashTable * allowed_nodes
Definition: internal.h:227
GList * promote
Definition: internal.h:224
GList * unpromoted
Definition: internal.h:226
GList * active
Definition: internal.h:219
GList * inactive
Definition: internal.h:220
GList * promoted
Definition: internal.h:225
GList * start
Definition: internal.h:221
pe_action_t * post
Definition: internal.h:215
pe_action_t * pre_done
Definition: internal.h:216
pe_action_t * pre
Definition: internal.h:214
GList * stop
Definition: internal.h:222
GSList * keys
Definition: internal.h:210
pe_action_t * post_done
Definition: internal.h:217
GList * demote
Definition: internal.h:223
char * value
Definition: nvpair.h:31
char * name
Definition: nvpair.h:30
char * uuid
Definition: pe_types.h:411
char * task
Definition: pe_types.h:410
pe_node_t * node
Definition: pe_types.h:407
int priority
Definition: pe_types.h:404
GHashTable * meta
Definition: pe_types.h:420
enum pe_action_flags flags
Definition: pe_types.h:415
struct pe_node_shared_s * details
Definition: pe_types.h:252
gboolean online
Definition: pe_types.h:220
const char * uname
Definition: pe_types.h:216
pe_resource_t * remote_rsc
Definition: pe_types.h:237
gboolean unclean
Definition: pe_types.h:224
gboolean remote_requires_reset
Definition: pe_types.h:231
GList * running_on
Definition: pe_types.h:373
GList * actions
Definition: pe_types.h:366
GHashTable * meta
Definition: pe_types.h:380
GList * children
Definition: pe_types.h:384
pe_working_set_t * cluster
Definition: pe_types.h:335
pe_resource_t * container
Definition: pe_types.h:387
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
pe_node_t * allocated_to
Definition: pe_types.h:370
unsigned long long flags
Definition: pe_types.h:355
enum rsc_role_e next_role
Definition: pe_types.h:378
enum rsc_role_e role
Definition: pe_types.h:377
GList * nodes
Definition: pe_types.h:164