pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
pcmk_sched_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>
14
15typedef struct notify_entry_s {
16 pe_resource_t *rsc;
17 pe_node_t *node;
19
33static gint
34compare_notify_entries(gconstpointer a, gconstpointer b)
35{
36 int tmp;
37 const notify_entry_t *entry_a = a;
38 const notify_entry_t *entry_b = b;
39
40 // NULL a or b is not actually possible
41 if ((entry_a == NULL) && (entry_b == NULL)) {
42 return 0;
43 }
44 if (entry_a == NULL) {
45 return 1;
46 }
47 if (entry_b == NULL) {
48 return -1;
49 }
50
51 // NULL resources sort first
52 if ((entry_a->rsc == NULL) && (entry_b->rsc == NULL)) {
53 return 0;
54 }
55 if (entry_a->rsc == NULL) {
56 return 1;
57 }
58 if (entry_b->rsc == NULL) {
59 return -1;
60 }
61
62 // Compare resource names
63 tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
64 if (tmp != 0) {
65 return tmp;
66 }
67
68 // Otherwise NULL nodes sort first
69 if ((entry_a->node == NULL) && (entry_b->node == NULL)) {
70 return 0;
71 }
72 if (entry_a->node == NULL) {
73 return 1;
74 }
75 if (entry_b->node == NULL) {
76 return -1;
77 }
78
79 // Finally, compare node names
80 return strcmp(entry_a->node->details->id, entry_b->node->details->id);
81}
82
92static notify_entry_t *
93dup_notify_entry(notify_entry_t *entry)
94{
95 notify_entry_t *dup = calloc(1, sizeof(notify_entry_t));
96
97 CRM_ASSERT(dup != NULL);
98 dup->rsc = entry->rsc;
99 dup->node = entry->node;
100 return dup;
101}
102
115static void
116get_node_names(GList *list, char **all_node_names, char **host_node_names)
117{
118 size_t all_len = 0;
119 size_t host_len = 0;
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 (GList *iter = list; iter != NULL; iter = iter->next) {
129 pe_node_t *node = (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, &all_len, 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, &host_len,
150 node->details->uname);
151 }
152 }
153
154 if ((all_node_names != NULL) && (*all_node_names == NULL)) {
155 *all_node_names = strdup(" ");
156 CRM_ASSERT(*all_node_names != NULL);
157 }
158 if ((host_node_names != NULL) && (*host_node_names == NULL)) {
159 *host_node_names = strdup(" ");
160 CRM_ASSERT(*host_node_names != NULL);
161 }
162}
163
177static GList *
178notify_entries_to_strings(GList *list, char **rsc_names, char **node_names)
179{
180 const char *last_rsc_id = NULL;
181 size_t rsc_names_len = 0;
182 size_t node_names_len = 0;
183
184 // Initialize output lists to NULL
185 if (rsc_names != NULL) {
186 *rsc_names = NULL;
187 }
188 if (node_names != NULL) {
189 *node_names = NULL;
190 }
191
192 // Sort input list for user-friendliness (and ease of filtering duplicates)
193 list = g_list_sort(list, compare_notify_entries);
194
195 for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
196 notify_entry_t *entry = (notify_entry_t *) gIter->data;
197
198 // Entry must have a resource (with ID)
199 CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
200 && (entry->rsc->id != NULL));
201 if ((entry == NULL) || (entry->rsc == NULL)
202 || (entry->rsc->id == NULL)) {
203 continue;
204 }
205
206 // Entry must have a node unless listing inactive resources
207 CRM_LOG_ASSERT((node_names == NULL) || (entry->node != NULL));
208 if ((node_names != NULL) && (entry->node == NULL)) {
209 continue;
210 }
211
212 // Don't add duplicates of a particular clone instance
213 if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
214 continue;
215 }
216 last_rsc_id = entry->rsc->id;
217
218 if (rsc_names != NULL) {
219 pcmk__add_word(rsc_names, &rsc_names_len, entry->rsc->id);
220 }
221 if ((node_names != NULL) && (entry->node->details->uname != NULL)) {
222 pcmk__add_word(node_names, &node_names_len,
223 entry->node->details->uname);
224 }
225 }
226
227 // If there are no entries, return "empty" lists
228 if ((rsc_names != NULL) && (*rsc_names == NULL)) {
229 *rsc_names = strdup(" ");
230 CRM_ASSERT(*rsc_names != NULL);
231 }
232 if ((node_names != NULL) && (*node_names == NULL)) {
233 *node_names = strdup(" ");
234 CRM_ASSERT(*node_names != NULL);
235 }
236
237 return list;
238}
239
248static void
249copy_meta_to_notify(gpointer key, gpointer value, gpointer user_data)
250{
251 pe_action_t *notify = (pe_action_t *) user_data;
252
253 /* Any existing meta-attributes (for example, the action timeout) are for
254 * the notify action itself, so don't override those.
255 */
256 if (g_hash_table_lookup(notify->meta, (const char *) key) != NULL) {
257 return;
258 }
259
260 g_hash_table_insert(notify->meta, strdup((const char *) key),
261 strdup((const char *) value));
262}
263
264static void
265add_notify_data_to_action_meta(notify_data_t *n_data, pe_action_t *action)
266{
267 for (GSList *item = n_data->keys; item; item = item->next) {
268 pcmk_nvpair_t *nvpair = item->data;
269
270 add_hash_param(action->meta, nvpair->name, nvpair->value);
271 }
272}
273
285static pe_action_t *
286new_notify_pseudo_action(pe_resource_t *rsc, const pe_action_t *action,
287 const char *notif_action, const char *notif_type)
288{
289 pe_action_t *notify = NULL;
290
291 notify = custom_action(rsc,
292 pcmk__notify_key(rsc->id, notif_type, action->task),
293 notif_action, NULL,
295 TRUE, rsc->cluster);
297 add_hash_param(notify->meta, "notify_key_type", notif_type);
298 add_hash_param(notify->meta, "notify_key_operation", action->task);
299 return notify;
300}
301
314static pe_action_t *
315new_notify_action(pe_resource_t *rsc, pe_node_t *node, pe_action_t *op,
316 pe_action_t *notify_done, notify_data_t *n_data)
317{
318 char *key = NULL;
319 pe_action_t *notify_action = NULL;
320 const char *value = NULL;
321 const char *task = NULL;
322 const char *skip_reason = NULL;
323
324 CRM_CHECK((rsc != NULL) && (node != NULL), return NULL);
325
326 // Ensure we have all the info we need
327 if (op == NULL) {
328 skip_reason = "no action";
329 } else if (notify_done == NULL) {
330 skip_reason = "no parent notification";
331 } else if (!node->details->online) {
332 skip_reason = "node offline";
333 } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
334 skip_reason = "original action not runnable";
335 }
336 if (skip_reason != NULL) {
337 pe_rsc_trace(rsc, "Skipping notify action for %s on %s: %s",
338 rsc->id, node->details->uname, skip_reason);
339 return NULL;
340 }
341
342 value = g_hash_table_lookup(op->meta, "notify_type"); // "pre" or "post"
343 task = g_hash_table_lookup(op->meta, "notify_operation"); // original action
344
345 pe_rsc_trace(rsc, "Creating notify action for %s on %s (%s-%s)",
346 rsc->id, node->details->uname, value, task);
347
348 // Create the notify action
349 key = pcmk__notify_key(rsc->id, value, task);
350 notify_action = custom_action(rsc, key, op->task, node,
352 TRUE, rsc->cluster);
353
354 // Add meta-data to notify action
355 g_hash_table_foreach(op->meta, copy_meta_to_notify, notify_action);
356 add_notify_data_to_action_meta(n_data, notify_action);
357
358 // Order notify after original action and before parent notification
359 order_actions(op, notify_action, pe_order_optional);
360 order_actions(notify_action, notify_done, pe_order_optional);
361 return notify_action;
362}
363
372static void
373new_post_notify_action(pe_resource_t *rsc, pe_node_t *node,
374 notify_data_t *n_data)
375{
376 pe_action_t *notify = 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 pe_action_t *mon = (pe_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, RSC_CANCEL, pcmk__str_none)) {
397 continue; // Not a recurring monitor
398 }
400 }
401}
402
436 pe_action_t *action, pe_action_t *complete)
437{
438 notify_data_t *n_data = NULL;
439
440 if (!pcmk_is_set(rsc->flags, pe_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, RSC_NOTIFY, "pre");
454 add_hash_param(n_data->pre->meta, "notify_type", "pre");
455 add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
456
457 // Create "pre-" notifications complete pseudo-action for clone
458 n_data->pre_done = new_notify_pseudo_action(rsc, action, RSC_NOTIFIED,
459 "confirmed-pre");
461 add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
463 "notify_operation", n_data->action);
464
465 // Order "pre-" -> "pre-" complete -> original action
466 order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
468 }
469
470 if (complete != NULL) { // Need "post-" pseudo-actions
471
472 // Create "post-" notify pseudo-action for clone
473 n_data->post = new_notify_pseudo_action(rsc, complete, RSC_NOTIFY,
474 "post");
475 n_data->post->priority = INFINITY;
476 if (pcmk_is_set(complete->flags, pe_action_runnable)) {
478 } else {
480 }
481 add_hash_param(n_data->post->meta, "notify_type", "post");
482 add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
483
484 // Create "post-" notifications complete pseudo-action for clone
485 n_data->post_done = new_notify_pseudo_action(rsc, complete,
487 "confirmed-post");
488 n_data->post_done->priority = INFINITY;
489 if (pcmk_is_set(complete->flags, pe_action_runnable)) {
491 } else {
493 }
494 add_hash_param(n_data->post_done->meta, "notify_type", "post");
496 "notify_operation", n_data->action);
497
498 // Order original action complete -> "post-" -> "post-" complete
499 order_actions(complete, n_data->post, pe_order_implies_then);
501 }
502
503 // If we created both, order "pre-" complete -> "post-"
504 if ((action != NULL) && (complete != NULL)) {
505 order_actions(n_data->pre_done, n_data->post, pe_order_optional);
506 }
507 return n_data;
508}
509
520static notify_entry_t *
521new_notify_entry(pe_resource_t *rsc, pe_node_t *node)
522{
523 notify_entry_t *entry = calloc(1, sizeof(notify_entry_t));
524
525 CRM_ASSERT(entry != NULL);
526 entry->rsc = rsc;
527 entry->node = node;
528 return entry;
529}
530
539static void
540collect_resource_data(pe_resource_t *rsc, bool activity, notify_data_t *n_data)
541{
542 GList *iter = NULL;
543 notify_entry_t *entry = NULL;
544 pe_node_t *node = NULL;
545
546 if (n_data->allowed_nodes == NULL) {
547 n_data->allowed_nodes = rsc->allowed_nodes;
548 }
549
550 // If this is a clone, call recursively for each instance
551 if (rsc->children != NULL) {
552 for (iter = rsc->children; iter != NULL; iter = iter->next) {
553 pe_resource_t *child = (pe_resource_t *) iter->data;
554
555 collect_resource_data(child, activity, n_data);
556 }
557 return;
558 }
559
560 // This is a notification for a single clone instance
561
562 if (rsc->running_on != NULL) {
563 node = rsc->running_on->data; // First is sufficient
564 }
565 entry = new_notify_entry(rsc, node);
566
567 // Add notification indicating the resource state
568 switch (rsc->role) {
569 case RSC_ROLE_STOPPED:
570 n_data->inactive = g_list_prepend(n_data->inactive, entry);
571 break;
572
573 case RSC_ROLE_STARTED:
574 n_data->active = g_list_prepend(n_data->active, entry);
575 break;
576
578 n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
579 n_data->active = g_list_prepend(n_data->active,
580 dup_notify_entry(entry));
581 break;
582
584 n_data->promoted = g_list_prepend(n_data->promoted, entry);
585 n_data->active = g_list_prepend(n_data->active,
586 dup_notify_entry(entry));
587 break;
588
589 default:
590 crm_err("Resource %s role on %s (%s) is not supported for "
591 "notifications (bug?)",
592 rsc->id, ((node == NULL)? "no node" : node->details->uname),
593 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 pe_action_t *op = (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#define add_notify_env(n_data, key, value) do { \
639 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
640 } while (0)
641
642#define add_notify_env_free(n_data, key, value) do { \
643 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
644 free(value); value = NULL; \
645 } while (0)
646
654static void
655add_notif_keys(pe_resource_t *rsc, notify_data_t *n_data)
656{
657 bool required = false; // Whether to make notify actions required
658 char *rsc_list = NULL;
659 char *node_list = NULL;
660 char *metal_list = NULL;
661 const char *source = NULL;
662 GList *nodes = NULL;
663
664 n_data->stop = notify_entries_to_strings(n_data->stop,
665 &rsc_list, &node_list);
666 if (!pcmk__str_eq(" ", rsc_list, pcmk__str_null_matches)
667 && pcmk__str_eq(n_data->action, RSC_STOP, pcmk__str_casei)) {
668 required = true;
669 }
670 add_notify_env_free(n_data, "notify_stop_resource", rsc_list);
671 add_notify_env_free(n_data, "notify_stop_uname", node_list);
672
673 if ((n_data->start != NULL)
674 && pcmk__str_eq(n_data->action, RSC_START, pcmk__str_none)) {
675 required = true;
676 }
677 n_data->start = notify_entries_to_strings(n_data->start,
678 &rsc_list, &node_list);
679 add_notify_env_free(n_data, "notify_start_resource", rsc_list);
680 add_notify_env_free(n_data, "notify_start_uname", node_list);
681
682 if ((n_data->demote != NULL)
683 && pcmk__str_eq(n_data->action, RSC_DEMOTE, pcmk__str_none)) {
684 required = true;
685 }
686 n_data->demote = notify_entries_to_strings(n_data->demote,
687 &rsc_list, &node_list);
688 add_notify_env_free(n_data, "notify_demote_resource", rsc_list);
689 add_notify_env_free(n_data, "notify_demote_uname", node_list);
690
691 if ((n_data->promote != NULL)
692 && pcmk__str_eq(n_data->action, RSC_PROMOTE, pcmk__str_none)) {
693 required = true;
694 }
695 n_data->promote = notify_entries_to_strings(n_data->promote,
696 &rsc_list, &node_list);
697 add_notify_env_free(n_data, "notify_promote_resource", rsc_list);
698 add_notify_env_free(n_data, "notify_promote_uname", node_list);
699
700 n_data->active = notify_entries_to_strings(n_data->active,
701 &rsc_list, &node_list);
702 add_notify_env_free(n_data, "notify_active_resource", rsc_list);
703 add_notify_env_free(n_data, "notify_active_uname", node_list);
704
705 n_data->unpromoted = notify_entries_to_strings(n_data->unpromoted,
706 &rsc_list, &node_list);
707 add_notify_env(n_data, "notify_unpromoted_resource", rsc_list);
708 add_notify_env(n_data, "notify_unpromoted_uname", node_list);
709
710 // Deprecated: kept for backward compatibility with older resource agents
711 add_notify_env_free(n_data, "notify_slave_resource", rsc_list);
712 add_notify_env_free(n_data, "notify_slave_uname", node_list);
713
714 n_data->promoted = notify_entries_to_strings(n_data->promoted,
715 &rsc_list, &node_list);
716 add_notify_env(n_data, "notify_promoted_resource", rsc_list);
717 add_notify_env(n_data, "notify_promoted_uname", node_list);
718
719 // Deprecated: kept for backward compatibility with older resource agents
720 add_notify_env_free(n_data, "notify_master_resource", rsc_list);
721 add_notify_env_free(n_data, "notify_master_uname", node_list);
722
723 n_data->inactive = notify_entries_to_strings(n_data->inactive,
724 &rsc_list, NULL);
725 add_notify_env_free(n_data, "notify_inactive_resource", rsc_list);
726
727 nodes = g_hash_table_get_values(n_data->allowed_nodes);
728 if (!pcmk__is_daemon) {
729 /* For display purposes, sort the node list, for consistent
730 * regression test output (while avoiding the performance hit
731 * for the live cluster).
732 */
733 nodes = g_list_sort(nodes, sort_node_uname);
734 }
735 get_node_names(nodes, &node_list, NULL);
736 add_notify_env_free(n_data, "notify_available_uname", node_list);
737 g_list_free(nodes);
738
739 source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
740 if (pcmk__str_eq("host", source, pcmk__str_none)) {
741 get_node_names(rsc->cluster->nodes, &node_list, &metal_list);
742 add_notify_env_free(n_data, "notify_all_hosts", metal_list);
743 } else {
744 get_node_names(rsc->cluster->nodes, &node_list, NULL);
745 }
746 add_notify_env_free(n_data, "notify_all_uname", node_list);
747
748 if (required && (n_data->pre != NULL)) {
751 }
752
753 if (required && (n_data->post != NULL)) {
756 }
757}
758
759/*
760 * \internal
761 * \brief Find any remote connection start relevant to an action
762 *
763 * \param[in] action Action to check
764 *
765 * \return If action is behind a remote connection, connection's start
766 */
767static pe_action_t *
768find_remote_start(pe_action_t *action)
769{
770 if ((action != NULL) && (action->node != NULL)) {
771 pe_resource_t *remote_rsc = action->node->details->remote_rsc;
772
773 if (remote_rsc != NULL) {
774 return find_first_action(remote_rsc->actions, NULL, RSC_START,
775 NULL);
776 }
777 }
778 return NULL;
779}
780
788static void
789create_notify_actions(pe_resource_t *rsc, notify_data_t *n_data)
790{
791 GList *iter = NULL;
792 pe_action_t *stop = NULL;
793 pe_action_t *start = NULL;
794 enum action_tasks task = text2task(n_data->action);
795
796 // If this is a clone, call recursively for each instance
797 if (rsc->children != NULL) {
798 g_list_foreach(rsc->children, (GFunc) create_notify_actions, n_data);
799 return;
800 }
801
802 // Add notification meta-attributes to original actions
803 for (iter = rsc->actions; iter != NULL; iter = iter->next) {
804 pe_action_t *op = (pe_action_t *) iter->data;
805
806 if (!pcmk_is_set(op->flags, pe_action_optional) && (op->node != NULL)) {
807 switch (text2task(op->task)) {
808 case start_rsc:
809 case stop_rsc:
810 case action_promote:
811 case action_demote:
812 add_notify_data_to_action_meta(n_data, op);
813 break;
814 default:
815 break;
816 }
817 }
818 }
819
820 // Skip notify action itself if original action was not needed
821 switch (task) {
822 case start_rsc:
823 if (n_data->start == NULL) {
824 pe_rsc_trace(rsc, "No notify action needed for %s %s",
825 rsc->id, n_data->action);
826 return;
827 }
828 break;
829
830 case action_promote:
831 if (n_data->promote == NULL) {
832 pe_rsc_trace(rsc, "No notify action needed for %s %s",
833 rsc->id, n_data->action);
834 return;
835 }
836 break;
837
838 case action_demote:
839 if (n_data->demote == NULL) {
840 pe_rsc_trace(rsc, "No notify action needed for %s %s",
841 rsc->id, n_data->action);
842 return;
843 }
844 break;
845
846 default:
847 // We cannot do same for stop because it might be implied by fencing
848 break;
849 }
850
851 pe_rsc_trace(rsc, "Creating notify actions for %s %s",
852 rsc->id, n_data->action);
853
854 // Create notify actions for stop or demote
855 if ((rsc->role != RSC_ROLE_STOPPED)
856 && ((task == stop_rsc) || (task == action_demote))) {
857
858 stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
859
860 for (iter = rsc->running_on; iter != NULL; iter = iter->next) {
861 pe_node_t *current_node = (pe_node_t *) iter->data;
862
863 /* If a stop is a pseudo-action implied by fencing, don't try to
864 * notify the node getting fenced.
865 */
866 if ((stop != NULL) && pcmk_is_set(stop->flags, pe_action_pseudo)
867 && (current_node->details->unclean
868 || current_node->details->remote_requires_reset)) {
869 continue;
870 }
871
872 new_notify_action(rsc, current_node, n_data->pre,
873 n_data->pre_done, n_data);
874
875 if ((task == action_demote) || (stop == NULL)
877 new_post_notify_action(rsc, current_node, n_data);
878 }
879 }
880 }
881
882 // Create notify actions for start or promote
883 if ((rsc->next_role != RSC_ROLE_STOPPED)
884 && ((task == start_rsc) || (task == action_promote))) {
885
886 start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
887 if (start != NULL) {
888 pe_action_t *remote_start = find_remote_start(start);
889
890 if ((remote_start != NULL)
891 && !pcmk_is_set(remote_start->flags, pe_action_runnable)) {
892 /* Start and promote actions for a clone instance behind
893 * a Pacemaker Remote connection happen after the
894 * connection starts. If the connection start is blocked, do
895 * not schedule notifications for these actions.
896 */
897 return;
898 }
899 }
900 if (rsc->allocated_to == NULL) {
901 pe_proc_err("Next role '%s' but %s is not allocated",
902 role2text(rsc->next_role), rsc->id);
903 return;
904 }
905 if ((task != start_rsc) || (start == NULL)
907
908 new_notify_action(rsc, rsc->allocated_to, n_data->pre,
909 n_data->pre_done, n_data);
910 }
911 new_post_notify_action(rsc, rsc->allocated_to, n_data);
912 }
913}
914
922void
924{
925 if ((rsc == NULL) || (n_data == NULL)) {
926 return;
927 }
928 collect_resource_data(rsc, true, n_data);
929 add_notif_keys(rsc, n_data);
930 create_notify_actions(rsc, n_data);
931}
932
939void
941{
942 if (n_data == NULL) {
943 return;
944 }
945 g_list_free_full(n_data->stop, free);
946 g_list_free_full(n_data->start, free);
947 g_list_free_full(n_data->demote, free);
948 g_list_free_full(n_data->promote, free);
949 g_list_free_full(n_data->promoted, free);
950 g_list_free_full(n_data->unpromoted, free);
951 g_list_free_full(n_data->active, free);
952 g_list_free_full(n_data->inactive, free);
953 pcmk_free_nvpairs(n_data->keys);
954 free(n_data);
955}
956
971void
973 pe_action_t *stonith_op)
974{
975 notify_data_t *n_data;
976
977 crm_info("Ordering notifications for implied %s after fencing", stop->uuid);
978 n_data = pcmk__clone_notif_pseudo_ops(rsc, RSC_STOP, NULL, stonith_op);
979 collect_resource_data(rsc, false, n_data);
980 add_notify_env(n_data, "notify_stop_resource", rsc->id);
981 add_notify_env(n_data, "notify_stop_uname", stop->node->details->uname);
982 create_notify_actions(uber_parent(rsc), n_data);
984}
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:122
enum action_tasks text2task(const char *task)
Definition: common.c:351
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:913
#define RSC_PROMOTE
Definition: crm.h:207
#define RSC_DEMOTE
Definition: crm.h:209
#define RSC_NOTIFY
Definition: crm.h:212
#define RSC_NOTIFIED
Definition: crm.h:213
#define RSC_START
Definition: crm.h:201
#define INFINITY
Definition: crm.h:99
#define RSC_STOP
Definition: crm.h:204
#define RSC_CANCEL
Definition: crm.h:196
#define crm_info(fmt, args...)
Definition: logging.h:361
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:210
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
#define crm_err(fmt, args...)
Definition: logging.h:358
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:227
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:301
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:102
const char * action
Definition: pcmk_fence.c:29
#define add_notify_env(n_data, key, value)
void pcmk__free_notification_data(notify_data_t *n_data)
void pcmk__create_notifications(pe_resource_t *rsc, notify_data_t *n_data)
notify_data_t * pcmk__clone_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
void pcmk__order_notifs_after_fencing(pe_action_t *stop, pe_resource_t *rsc, pe_action_t *stonith_op)
#define add_notify_env_free(n_data, key, value)
struct notify_entry_s notify_entry_t
#define pe_rsc_notify
Definition: pe_types.h:261
@ pe_order_implies_then
Definition: pe_types.h:503
@ pe_order_optional
Definition: pe_types.h:499
@ pe_action_optional
Definition: pe_types.h:308
@ pe_action_runnable
Definition: pe_types.h:307
@ pe_action_pseudo
Definition: pe_types.h:306
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, pe_node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Create or update an action object.
Definition: utils.c:730
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1541
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition: utils.c:217
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1906
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:22
#define pe_proc_err(fmt...)
Definition: internal.h:34
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:70
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:61
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
@ pcmk__str_casei
const char * action
Definition: internal.h:197
GHashTable * allowed_nodes
Definition: internal.h:212
GList * promote
Definition: internal.h:209
GList * unpromoted
Definition: internal.h:211
GList * active
Definition: internal.h:204
GList * inactive
Definition: internal.h:205
GList * promoted
Definition: internal.h:210
GList * start
Definition: internal.h:206
pe_action_t * post
Definition: internal.h:200
pe_action_t * pre_done
Definition: internal.h:201
pe_action_t * pre
Definition: internal.h:199
GList * stop
Definition: internal.h:207
GSList * keys
Definition: internal.h:195
pe_action_t * post_done
Definition: internal.h:202
GList * demote
Definition: internal.h:208
char * value
Definition: nvpair.h:31
char * name
Definition: nvpair.h:30
char * uuid
Definition: pe_types.h:429
char * task
Definition: pe_types.h:428
pe_node_t * node
Definition: pe_types.h:425
int priority
Definition: pe_types.h:422
GHashTable * meta
Definition: pe_types.h:438
enum pe_action_flags flags
Definition: pe_types.h:433
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:380
GList * actions
Definition: pe_types.h:373
GHashTable * meta
Definition: pe_types.h:387
GList * children
Definition: pe_types.h:391
pe_working_set_t * cluster
Definition: pe_types.h:342
pe_resource_t * container
Definition: pe_types.h:394
char * id
Definition: pe_types.h:336
GHashTable * allowed_nodes
Definition: pe_types.h:382
pe_node_t * allocated_to
Definition: pe_types.h:377
unsigned long long flags
Definition: pe_types.h:362
enum rsc_role_e next_role
Definition: pe_types.h:385
enum rsc_role_e role
Definition: pe_types.h:384
GList * nodes
Definition: pe_types.h:164