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