pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_notif.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2021 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
14extern bool pcmk__is_daemon;
15
16typedef struct notify_entry_s {
17 pe_resource_t *rsc;
18 pe_node_t *node;
20
21static gint
22sort_notify_entries(gconstpointer a, gconstpointer b)
23{
24 int tmp;
25 const notify_entry_t *entry_a = a;
26 const notify_entry_t *entry_b = b;
27
28 if (entry_a == NULL && entry_b == NULL) {
29 return 0;
30 }
31 if (entry_a == NULL) {
32 return 1;
33 }
34 if (entry_b == NULL) {
35 return -1;
36 }
37
38 if (entry_a->rsc == NULL && entry_b->rsc == NULL) {
39 return 0;
40 }
41 if (entry_a->rsc == NULL) {
42 return 1;
43 }
44 if (entry_b->rsc == NULL) {
45 return -1;
46 }
47
48 tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
49 if (tmp != 0) {
50 return tmp;
51 }
52
53 if (entry_a->node == NULL && entry_b->node == NULL) {
54 return 0;
55 }
56 if (entry_a->node == NULL) {
57 return 1;
58 }
59 if (entry_b->node == NULL) {
60 return -1;
61 }
62
63 return strcmp(entry_a->node->details->id, entry_b->node->details->id);
64}
65
66static notify_entry_t *dup_notify_entry(notify_entry_t *entry)
67{
68 notify_entry_t *dup = malloc(sizeof(notify_entry_t));
69
70 CRM_ASSERT(dup != NULL);
71 dup->rsc = entry->rsc;
72 dup->node = entry->node;
73 return dup;
74}
75
76static void
77expand_node_list(GList *list, char **uname, char **metal)
78{
79 GList *gIter = NULL;
80 char *node_list = NULL;
81 char *metal_list = NULL;
82 size_t node_list_len = 0;
83 size_t metal_list_len = 0;
84
85 CRM_ASSERT(uname != NULL);
86 if (list == NULL) {
87 *uname = strdup(" ");
88 if(metal) {
89 *metal = strdup(" ");
90 }
91 return;
92 }
93
94 for (gIter = list; gIter != NULL; gIter = gIter->next) {
95 pe_node_t *node = (pe_node_t *) gIter->data;
96
97 if (node->details->uname == NULL) {
98 continue;
99 }
100 pcmk__add_word(&node_list, &node_list_len, node->details->uname);
101 if(metal) {
102 if(node->details->remote_rsc
103 && node->details->remote_rsc->container
104 && node->details->remote_rsc->container->running_on) {
105 node = pe__current_node(node->details->remote_rsc->container);
106 }
107
108 if (node->details->uname == NULL) {
109 continue;
110 }
111 pcmk__add_word(&metal_list, &metal_list_len, node->details->uname);
112 }
113 }
114
115 *uname = node_list;
116 if(metal) {
117 *metal = metal_list;
118 }
119}
120
131static GList *
132expand_list(GList *list, char **rsc_list, char **node_list)
133{
134 const char *last_rsc_id = NULL;
135 size_t rsc_list_len = 0;
136 size_t node_list_len = 0;
137
138 CRM_CHECK(rsc_list != NULL, return list);
139
140 // If there are no entries, return "empty" lists
141 if (list == NULL) {
142 *rsc_list = strdup(" ");
143 if (node_list) {
144 *node_list = strdup(" ");
145 }
146 return list;
147 }
148
149 // Initialize output lists to NULL
150 *rsc_list = NULL;
151 if (node_list) {
152 *node_list = NULL;
153 }
154
155 // Sort input list for user-friendliness (and ease of filtering duplicates)
156 list = g_list_sort(list, sort_notify_entries);
157
158 for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
159 notify_entry_t *entry = (notify_entry_t *) gIter->data;
160
161 // Entry must have a resource (with ID)
162 CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
163 && (entry->rsc->id != NULL));
164 if ((entry == NULL) || (entry->rsc == NULL)
165 || (entry->rsc->id == NULL)) {
166 continue;
167 }
168
169 // Entry must have a node unless listing inactive resources
170 CRM_LOG_ASSERT((node_list == NULL) || (entry->node != NULL));
171 if ((node_list != NULL) && (entry->node == NULL)) {
172 continue;
173 }
174
175 // Don't add duplicates of a particular clone instance
176 if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
177 continue;
178 }
179 last_rsc_id = entry->rsc->id;
180 pcmk__add_word(rsc_list, &rsc_list_len, entry->rsc->id);
181 if ((node_list != NULL) && (entry->node->details->uname != NULL)) {
182 pcmk__add_word(node_list, &node_list_len,
183 entry->node->details->uname);
184 }
185 }
186 return list;
187}
188
189static void
190dup_attr(gpointer key, gpointer value, gpointer user_data)
191{
192 add_hash_param(user_data, key, value);
193}
194
195static void
196add_notify_data_to_action_meta(notify_data_t *n_data, pe_action_t *action)
197{
198 for (GSList *item = n_data->keys; item; item = item->next) {
199 pcmk_nvpair_t *nvpair = item->data;
200
201 add_hash_param(action->meta, nvpair->name, nvpair->value);
202 }
203}
204
205static pe_action_t *
206pe_notify(pe_resource_t * rsc, pe_node_t * node, pe_action_t * op, pe_action_t * confirm,
207 notify_data_t * n_data, pe_working_set_t * data_set)
208{
209 char *key = NULL;
210 pe_action_t *trigger = NULL;
211 const char *value = NULL;
212 const char *task = NULL;
213
214 if (op == NULL || confirm == NULL) {
215 pe_rsc_trace(rsc, "Op=%p confirm=%p", op, confirm);
216 return NULL;
217 }
218
219 CRM_CHECK(rsc != NULL, return NULL);
220 CRM_CHECK(node != NULL, return NULL);
221
222 if (node->details->online == FALSE) {
223 pe_rsc_trace(rsc, "Skipping notification for %s: node offline", rsc->id);
224 return NULL;
225 } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
226 pe_rsc_trace(rsc, "Skipping notification for %s: not runnable", op->uuid);
227 return NULL;
228 }
229
230 value = g_hash_table_lookup(op->meta, "notify_type");
231 task = g_hash_table_lookup(op->meta, "notify_operation");
232
233 pe_rsc_trace(rsc, "Creating notify actions for %s: %s (%s-%s)", op->uuid, rsc->id, value, task);
234
235 key = pcmk__notify_key(rsc->id, value, task);
236 trigger = custom_action(rsc, key, op->task, node,
238 TRUE, data_set);
239 g_hash_table_foreach(op->meta, dup_attr, trigger->meta);
240 add_notify_data_to_action_meta(n_data, trigger);
241
242 /* pseudo_notify before notify */
243 pe_rsc_trace(rsc, "Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id,
244 op->id);
245
246 order_actions(op, trigger, pe_order_optional);
247 order_actions(trigger, confirm, pe_order_optional);
248 return trigger;
249}
250
251static void
252pe_post_notify(pe_resource_t * rsc, pe_node_t * node, notify_data_t * n_data, pe_working_set_t * data_set)
253{
254 pe_action_t *notify = NULL;
255
256 CRM_CHECK(rsc != NULL, return);
257
258 if (n_data->post == NULL) {
259 return; /* Nothing to do */
260 }
261
262 notify = pe_notify(rsc, node, n_data->post, n_data->post_done, n_data, data_set);
263
264 if (notify != NULL) {
265 notify->priority = INFINITY;
266 }
267
268 if (n_data->post_done) {
269 GList *gIter = rsc->actions;
270
271 for (; gIter != NULL; gIter = gIter->next) {
272 pe_action_t *mon = (pe_action_t *) gIter->data;
273 const char *interval_ms_s = g_hash_table_lookup(mon->meta,
275
276 if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
277 pe_rsc_trace(rsc, "Skipping %s: interval", mon->uuid);
278 continue;
279 } else if (pcmk__str_eq(mon->task, RSC_CANCEL, pcmk__str_casei)) {
280 pe_rsc_trace(rsc, "Skipping %s: cancel", mon->uuid);
281 continue;
282 }
283
285 }
286 }
287}
288
291 pe_action_t * end, pe_working_set_t * data_set)
292{
293 /* Create the pseudo ops that precede and follow the actual notifications */
294
295 /*
296 * Creates two sequences (conditional on start and end being supplied):
297 * pre_notify -> pre_notify_complete -> start, and
298 * end -> post_notify -> post_notify_complete
299 *
300 * 'start' and 'end' may be the same event or ${X} and ${X}ed as per clones
301 */
302 char *key = NULL;
303 notify_data_t *n_data = NULL;
304
305 if (!pcmk_is_set(rsc->flags, pe_rsc_notify)) {
306 return NULL;
307 }
308
309 n_data = calloc(1, sizeof(notify_data_t));
310 n_data->action = action;
311
312 if (start) {
313 /* create pre-event notification wrappers */
314 key = pcmk__notify_key(rsc->id, "pre", start->task);
315 n_data->pre =
316 custom_action(rsc, key, RSC_NOTIFY, NULL,
318 TRUE, data_set);
320
321 add_hash_param(n_data->pre->meta, "notify_type", "pre");
322 add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
323
324 add_hash_param(n_data->pre->meta, "notify_key_type", "pre");
325 add_hash_param(n_data->pre->meta, "notify_key_operation", start->task);
326
327 /* create pre_notify_complete */
328 key = pcmk__notify_key(rsc->id, "confirmed-pre", start->task);
329 n_data->pre_done = custom_action(rsc, key, RSC_NOTIFIED, NULL,
331 TRUE, data_set);
334
335 add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
336 add_hash_param(n_data->pre_done->meta, "notify_operation", n_data->action);
337
338 add_hash_param(n_data->pre_done->meta, "notify_key_type", "confirmed-pre");
339 add_hash_param(n_data->pre_done->meta, "notify_key_operation", start->task);
340
342 order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
343 }
344
345 if (end) {
346 /* create post-event notification wrappers */
347 key = pcmk__notify_key(rsc->id, "post", end->task);
348 n_data->post = custom_action(rsc, key, RSC_NOTIFY, NULL,
350 TRUE, data_set);
351
352 n_data->post->priority = INFINITY;
356 } else {
358 }
359
360 add_hash_param(n_data->post->meta, "notify_type", "post");
361 add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
362
363 add_hash_param(n_data->post->meta, "notify_key_type", "post");
364 add_hash_param(n_data->post->meta, "notify_key_operation", end->task);
365
366 /* create post_notify_complete */
367 key = pcmk__notify_key(rsc->id, "confirmed-post", end->task);
368 n_data->post_done = custom_action(rsc, key, RSC_NOTIFIED, NULL,
370 TRUE, data_set);
371
372 n_data->post_done->priority = INFINITY;
376 } else {
378 }
379
380 add_hash_param(n_data->post_done->meta, "notify_type", "post");
381 add_hash_param(n_data->post_done->meta, "notify_operation", n_data->action);
382
383 add_hash_param(n_data->post_done->meta, "notify_key_type", "confirmed-post");
384 add_hash_param(n_data->post_done->meta, "notify_key_operation", end->task);
385
388 }
389
390 if (start && end) {
391 order_actions(n_data->pre_done, n_data->post, pe_order_optional);
392 }
393 return n_data;
394}
395
396void
397collect_notification_data(pe_resource_t * rsc, gboolean state, gboolean activity,
398 notify_data_t * n_data)
399{
400
401 if(n_data->allowed_nodes == NULL) {
402 n_data->allowed_nodes = rsc->allowed_nodes;
403 }
404
405 if (rsc->children) {
406 GList *gIter = rsc->children;
407
408 for (; gIter != NULL; gIter = gIter->next) {
409 pe_resource_t *child = (pe_resource_t *) gIter->data;
410
411 collect_notification_data(child, state, activity, n_data);
412 }
413 return;
414 }
415
416 if (state) {
417 notify_entry_t *entry = NULL;
418
419 entry = calloc(1, sizeof(notify_entry_t));
420 entry->rsc = rsc;
421 if (rsc->running_on) {
422 /* we only take the first one */
423 entry->node = rsc->running_on->data;
424 }
425
426 pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(rsc->role));
427
428 switch (rsc->role) {
429 case RSC_ROLE_STOPPED:
430 n_data->inactive = g_list_prepend(n_data->inactive, entry);
431 break;
432 case RSC_ROLE_STARTED:
433 n_data->active = g_list_prepend(n_data->active, entry);
434 break;
436 n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
437 n_data->active = g_list_prepend(n_data->active,
438 dup_notify_entry(entry));
439 break;
441 n_data->promoted = g_list_prepend(n_data->promoted, entry);
442 n_data->active = g_list_prepend(n_data->active,
443 dup_notify_entry(entry));
444 break;
445 default:
446 crm_err("Unsupported notify role");
447 free(entry);
448 break;
449 }
450 }
451
452 if (activity) {
453 notify_entry_t *entry = NULL;
454 enum action_tasks task;
455
456 GList *gIter = rsc->actions;
457
458 for (; gIter != NULL; gIter = gIter->next) {
459 pe_action_t *op = (pe_action_t *) gIter->data;
460
462 && (op->node != NULL)) {
463
464 task = text2task(op->task);
465
466 if(task == stop_rsc && op->node->details->unclean) {
467 // Create anyway (additional noise if node can't be fenced)
468 } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
469 continue;
470 }
471
472 entry = calloc(1, sizeof(notify_entry_t));
473 entry->node = op->node;
474 entry->rsc = rsc;
475
476 switch (task) {
477 case start_rsc:
478 n_data->start = g_list_prepend(n_data->start, entry);
479 break;
480 case stop_rsc:
481 n_data->stop = g_list_prepend(n_data->stop, entry);
482 break;
483 case action_promote:
484 n_data->promote = g_list_prepend(n_data->promote, entry);
485 break;
486 case action_demote:
487 n_data->demote = g_list_prepend(n_data->demote, entry);
488 break;
489 default:
490 free(entry);
491 break;
492 }
493 }
494 }
495 }
496}
497
498#define add_notify_env(n_data, key, value) do { \
499 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
500 } while (0)
501
502#define add_notify_env_free(n_data, key, value) do { \
503 n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
504 free(value); value = NULL; \
505 } while (0)
506
515void
517 notify_data_t *n_data,
518 pe_working_set_t *data_set)
519{
520 bool required = false; // Whether to make notify actions required
521 char *rsc_list = NULL;
522 char *node_list = NULL;
523 char *metal_list = NULL;
524 const char *source = NULL;
525 GList *nodes = NULL;
526
527 n_data->stop = expand_list(n_data->stop, &rsc_list, &node_list);
528 if (!pcmk__str_eq(" ", rsc_list, pcmk__str_null_matches)
529 && pcmk__str_eq(n_data->action, RSC_STOP, pcmk__str_casei)) {
530 required = true;
531 }
532 add_notify_env_free(n_data, "notify_stop_resource", rsc_list);
533 add_notify_env_free(n_data, "notify_stop_uname", node_list);
534
535 if ((n_data->start != NULL)
536 && pcmk__str_eq(n_data->action, RSC_START, pcmk__str_casei)) {
537 required = true;
538 }
539 n_data->start = expand_list(n_data->start, &rsc_list, &node_list);
540 add_notify_env_free(n_data, "notify_start_resource", rsc_list);
541 add_notify_env_free(n_data, "notify_start_uname", node_list);
542
543 if ((n_data->demote != NULL)
544 && pcmk__str_eq(n_data->action, RSC_DEMOTE, pcmk__str_casei)) {
545 required = true;
546 }
547 n_data->demote = expand_list(n_data->demote, &rsc_list, &node_list);
548 add_notify_env_free(n_data, "notify_demote_resource", rsc_list);
549 add_notify_env_free(n_data, "notify_demote_uname", node_list);
550
551 if ((n_data->promote != NULL)
552 && pcmk__str_eq(n_data->action, RSC_PROMOTE, pcmk__str_casei)) {
553 required = true;
554 }
555 n_data->promote = expand_list(n_data->promote, &rsc_list, &node_list);
556 add_notify_env_free(n_data, "notify_promote_resource", rsc_list);
557 add_notify_env_free(n_data, "notify_promote_uname", node_list);
558
559 n_data->active = expand_list(n_data->active, &rsc_list, &node_list);
560 add_notify_env_free(n_data, "notify_active_resource", rsc_list);
561 add_notify_env_free(n_data, "notify_active_uname", node_list);
562
563 n_data->unpromoted = expand_list(n_data->unpromoted, &rsc_list, &node_list);
564 add_notify_env(n_data, "notify_unpromoted_resource", rsc_list);
565 add_notify_env(n_data, "notify_unpromoted_uname", node_list);
566
567 // Deprecated: kept for backward compatibility with older resource agents
568 add_notify_env_free(n_data, "notify_slave_resource", rsc_list);
569 add_notify_env_free(n_data, "notify_slave_uname", node_list);
570
571 n_data->promoted = expand_list(n_data->promoted, &rsc_list, &node_list);
572 add_notify_env(n_data, "notify_promoted_resource", rsc_list);
573 add_notify_env(n_data, "notify_promoted_uname", node_list);
574
575 // Deprecated: kept for backward compatibility with older resource agents
576 add_notify_env_free(n_data, "notify_master_resource", rsc_list);
577 add_notify_env_free(n_data, "notify_master_uname", node_list);
578
579 n_data->inactive = expand_list(n_data->inactive, &rsc_list, NULL);
580 add_notify_env_free(n_data, "notify_inactive_resource", rsc_list);
581
582 nodes = g_hash_table_get_values(n_data->allowed_nodes);
583 if (!pcmk__is_daemon) {
584 /* If printing to stdout, sort the node list, for consistent
585 * regression test output (while avoiding the performance hit
586 * for the live cluster).
587 */
588 nodes = g_list_sort(nodes, sort_node_uname);
589 }
590 expand_node_list(nodes, &node_list, NULL);
591 add_notify_env_free(n_data, "notify_available_uname", node_list);
592 g_list_free(nodes);
593
594 source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
595 if (pcmk__str_eq("host", source, pcmk__str_casei)) {
596 expand_node_list(data_set->nodes, &node_list, &metal_list);
597 add_notify_env_free(n_data, "notify_all_hosts", metal_list);
598 } else {
599 expand_node_list(data_set->nodes, &node_list, NULL);
600 }
601 add_notify_env_free(n_data, "notify_all_uname", node_list);
602
603 if (required && n_data->pre) {
606 }
607
608 if (required && n_data->post) {
611 }
612}
613
614/*
615 * \internal
616 * \brief Find any remote connection start relevant to an action
617 *
618 * \param[in] action Action to chek
619 *
620 * \return If action is behind a remote connection, connection's start
621 */
622static pe_action_t *
623find_remote_start(pe_action_t *action)
624{
625 if (action && action->node) {
626 pe_resource_t *remote_rsc = action->node->details->remote_rsc;
627
628 if (remote_rsc) {
629 return find_first_action(remote_rsc->actions, NULL, RSC_START,
630 NULL);
631 }
632 }
633 return NULL;
634}
635
636void
638{
639 GList *gIter = NULL;
640 pe_action_t *stop = NULL;
641 pe_action_t *start = NULL;
642 enum action_tasks task = text2task(n_data->action);
643
644 if (rsc->children) {
645 gIter = rsc->children;
646 for (; gIter != NULL; gIter = gIter->next) {
647 pe_resource_t *child = (pe_resource_t *) gIter->data;
648
649 create_notifications(child, n_data, data_set);
650 }
651 return;
652 }
653
654 /* Copy notification details into standard ops */
655
656 for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
657 pe_action_t *op = (pe_action_t *) gIter->data;
658
660 && (op->node != NULL)) {
661
662 enum action_tasks t = text2task(op->task);
663
664 switch (t) {
665 case start_rsc:
666 case stop_rsc:
667 case action_promote:
668 case action_demote:
669 add_notify_data_to_action_meta(n_data, op);
670 break;
671 default:
672 break;
673 }
674 }
675 }
676
677 switch (task) {
678 case start_rsc:
679 if (n_data->start == NULL) {
680 pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
681 n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
682 return;
683 }
684 break;
685 case action_promote:
686 if (n_data->promote == NULL) {
687 pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
688 n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
689 return;
690 }
691 break;
692 case action_demote:
693 if (n_data->demote == NULL) {
694 pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
695 n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
696 return;
697 }
698 break;
699 default:
700 /* We cannot do the same for stop_rsc/n_data->stop at it
701 * might be implied by fencing
702 */
703 break;
704 }
705
706 pe_rsc_trace(rsc, "Creating notifications for: %s.%s (%s->%s)",
707 n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
708
709 stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
710 start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
711
712 /* stop / demote */
713 if (rsc->role != RSC_ROLE_STOPPED) {
714 if (task == stop_rsc || task == action_demote) {
715 gIter = rsc->running_on;
716 for (; gIter != NULL; gIter = gIter->next) {
717 pe_node_t *current_node = (pe_node_t *) gIter->data;
718
719 /* if this stop action is a pseudo action as a result of the current
720 * node being fenced, this stop action is implied by the fencing
721 * action. There's no reason to send the fenced node a stop notification */
722 if (stop && pcmk_is_set(stop->flags, pe_action_pseudo) &&
723 (current_node->details->unclean || current_node->details->remote_requires_reset) ) {
724
725 continue;
726 }
727
728 pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set);
729 if (task == action_demote || stop == NULL
731 pe_post_notify(rsc, current_node, n_data, data_set);
732 }
733 }
734 }
735 }
736
737 /* start / promote */
738 if (rsc->next_role != RSC_ROLE_STOPPED) {
739 if (rsc->allocated_to == NULL) {
740 pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role),
741 rsc->id);
742
743 } else if (task == start_rsc || task == action_promote) {
744
745 if (start) {
746 pe_action_t *remote_start = find_remote_start(start);
747
748 if (remote_start
749 && !pcmk_is_set(remote_start->flags, pe_action_runnable)) {
750 /* Start and promote actions for a clone instance behind
751 * a Pacemaker Remote connection happen after the
752 * connection starts. If the connection start is blocked, do
753 * not schedule notifications for these actions.
754 */
755 return;
756 }
757 }
758 if ((task != start_rsc) || (start == NULL)
760
761 pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set);
762 }
763 pe_post_notify(rsc, rsc->allocated_to, n_data, data_set);
764 }
765 }
766}
767
768void
770{
771 if (n_data == NULL) {
772 return;
773 }
774
775 g_list_free_full(n_data->stop, free);
776 g_list_free_full(n_data->start, free);
777 g_list_free_full(n_data->demote, free);
778 g_list_free_full(n_data->promote, free);
779 g_list_free_full(n_data->promoted, free);
780 g_list_free_full(n_data->unpromoted, free);
781 g_list_free_full(n_data->active, free);
782 g_list_free_full(n_data->inactive, free);
783 pcmk_free_nvpairs(n_data->keys);
784 free(n_data);
785}
786
787void
789 pe_action_t *stonith_op,
790 pe_working_set_t *data_set)
791{
792 notify_data_t *n_data;
793
794 crm_info("Creating secondary notification for %s", action->uuid);
795 n_data = create_notification_boundaries(rsc, RSC_STOP, NULL, stonith_op,
796 data_set);
797 collect_notification_data(rsc, TRUE, FALSE, n_data);
798 add_notify_env(n_data, "notify_stop_resource", rsc->id);
799 add_notify_env(n_data, "notify_stop_uname", action->node->details->uname);
800 create_notifications(uber_parent(rsc), n_data, data_set);
802}
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition operations.c:229
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
enum action_tasks text2task(const char *task)
Definition common.c:354
const char * role2text(enum rsc_role_e role)
Definition common.c:459
action_tasks
Definition common.h:62
@ start_rsc
Definition common.h:67
@ action_demote
Definition common.h:73
@ stop_rsc
Definition common.h:65
@ action_promote
Definition common.h:71
@ 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:903
char uname[MAX_NAME]
Definition cpg.c:5
#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:353
#define CRM_LOG_ASSERT(expr)
Definition logging.h:202
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_err(fmt, args...)
Definition logging.h:350
#define XML_RSC_ATTR_TARGET
Definition msg_xml.h:221
#define XML_LRM_ATTR_INTERVAL_MS
Definition msg_xml.h:295
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition nvpair.c:103
const char * action
Definition pcmk_fence.c:30
void create_notifications(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
#define add_notify_env(n_data, key, value)
void free_notification_data(notify_data_t *n_data)
void create_secondary_notification(pe_action_t *action, pe_resource_t *rsc, pe_action_t *stonith_op, pe_working_set_t *data_set)
void collect_notification_data(pe_resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data)
bool pcmk__is_daemon
Definition logging.c:47
#define add_notify_env_free(n_data, key, value)
struct notify_entry_s notify_entry_t
notify_data_t * create_notification_boundaries(pe_resource_t *rsc, const char *action, pe_action_t *start, pe_action_t *end, pe_working_set_t *data_set)
void pcmk__create_notification_keys(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
#define pe_rsc_notify
Definition pe_types.h:253
@ pe_order_implies_then
Definition pe_types.h:490
@ pe_order_optional
Definition pe_types.h:486
@ pe_action_optional
Definition pe_types.h:294
@ pe_action_runnable
Definition pe_types.h:293
@ pe_action_pseudo
Definition pe_types.h:292
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)
Definition utils.c:415
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition utils.c:1428
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition utils.c:218
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition utils.c:1808
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:20
#define pe_proc_err(fmt...)
Definition internal.h:32
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:68
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:59
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:579
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
const char * action
Definition internal.h:194
GHashTable * allowed_nodes
Definition internal.h:209
GList * promote
Definition internal.h:206
GList * unpromoted
Definition internal.h:208
GList * active
Definition internal.h:201
GList * inactive
Definition internal.h:202
GList * promoted
Definition internal.h:207
GList * start
Definition internal.h:203
pe_action_t * post
Definition internal.h:197
pe_action_t * pre_done
Definition internal.h:198
pe_action_t * pre
Definition internal.h:196
GList * stop
Definition internal.h:204
GSList * keys
Definition internal.h:192
pe_action_t * post_done
Definition internal.h:199
GList * demote
Definition internal.h:205
char * value
Definition nvpair.h:30
char * name
Definition nvpair.h:29
char * uuid
Definition pe_types.h:416
char * task
Definition pe_types.h:415
pe_node_t * node
Definition pe_types.h:412
GHashTable * meta
Definition pe_types.h:425
enum pe_action_flags flags
Definition pe_types.h:420
struct pe_node_shared_s * details
Definition pe_types.h:244
gboolean online
Definition pe_types.h:213
gboolean unclean
Definition pe_types.h:217
gboolean remote_requires_reset
Definition pe_types.h:224
GList * running_on
Definition pe_types.h:367
GList * actions
Definition pe_types.h:360
GHashTable * meta
Definition pe_types.h:374
GList * children
Definition pe_types.h:378
GHashTable * allowed_nodes
Definition pe_types.h:369
pe_node_t * allocated_to
Definition pe_types.h:364
unsigned long long flags
Definition pe_types.h:349
enum rsc_role_e next_role
Definition pe_types.h:372
enum rsc_role_e role
Definition pe_types.h:371