pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
14 extern bool pcmk__is_daemon;
15 
16 typedef struct notify_entry_s {
17  pe_resource_t *rsc;
18  pe_node_t *node;
20 
21 static gint
22 sort_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 
66 static 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 
76 static void
77 expand_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 
131 static GList *
132 expand_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 
189 static void
190 dup_attr(gpointer key, gpointer value, gpointer user_data)
191 {
192  add_hash_param(user_data, key, value);
193 }
194 
195 static void
196 add_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 
205 static pe_action_t *
206 pe_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 
251 static void
252 pe_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 
290 create_notification_boundaries(pe_resource_t * rsc, const char *action, pe_action_t * start,
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);
319 
320  update_action_flags(n_data->pre, pe_action_pseudo, __func__, __LINE__);
321  update_action_flags(n_data->pre, pe_action_runnable, __func__,
322  __LINE__);
323 
324  add_hash_param(n_data->pre->meta, "notify_type", "pre");
325  add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
326 
327  add_hash_param(n_data->pre->meta, "notify_key_type", "pre");
328  add_hash_param(n_data->pre->meta, "notify_key_operation", start->task);
329 
330  /* create pre_notify_complete */
331  key = pcmk__notify_key(rsc->id, "confirmed-pre", start->task);
332  n_data->pre_done = custom_action(rsc, key, RSC_NOTIFIED, NULL,
334  TRUE, data_set);
335 
336  update_action_flags(n_data->pre_done, pe_action_pseudo, __func__,
337  __LINE__);
339  __LINE__);
340 
341  add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
342  add_hash_param(n_data->pre_done->meta, "notify_operation", n_data->action);
343 
344  add_hash_param(n_data->pre_done->meta, "notify_key_type", "confirmed-pre");
345  add_hash_param(n_data->pre_done->meta, "notify_key_operation", start->task);
346 
347  order_actions(n_data->pre_done, start, pe_order_optional);
348  order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
349  }
350 
351  if (end) {
352  /* create post-event notification wrappers */
353  key = pcmk__notify_key(rsc->id, "post", end->task);
354  n_data->post = custom_action(rsc, key, RSC_NOTIFY, NULL,
356  TRUE, data_set);
357 
358  n_data->post->priority = INFINITY;
359  update_action_flags(n_data->post, pe_action_pseudo, __func__,
360  __LINE__);
361  if (pcmk_is_set(end->flags, pe_action_runnable)) {
362  update_action_flags(n_data->post, pe_action_runnable, __func__,
363  __LINE__);
364  } else {
366  __func__, __LINE__);
367  }
368 
369  add_hash_param(n_data->post->meta, "notify_type", "post");
370  add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
371 
372  add_hash_param(n_data->post->meta, "notify_key_type", "post");
373  add_hash_param(n_data->post->meta, "notify_key_operation", end->task);
374 
375  /* create post_notify_complete */
376  key = pcmk__notify_key(rsc->id, "confirmed-post", end->task);
377  n_data->post_done = custom_action(rsc, key, RSC_NOTIFIED, NULL,
379  TRUE, data_set);
380 
381  n_data->post_done->priority = INFINITY;
383  __LINE__);
384  if (pcmk_is_set(end->flags, pe_action_runnable)) {
386  __func__, __LINE__);
387  } else {
389  __func__, __LINE__);
390  }
391 
392  add_hash_param(n_data->post_done->meta, "notify_type", "post");
393  add_hash_param(n_data->post_done->meta, "notify_operation", n_data->action);
394 
395  add_hash_param(n_data->post_done->meta, "notify_key_type", "confirmed-post");
396  add_hash_param(n_data->post_done->meta, "notify_key_operation", end->task);
397 
400  }
401 
402  if (start && end) {
403  order_actions(n_data->pre_done, n_data->post, pe_order_optional);
404  }
405  return n_data;
406 }
407 
408 void
409 collect_notification_data(pe_resource_t * rsc, gboolean state, gboolean activity,
410  notify_data_t * n_data)
411 {
412 
413  if(n_data->allowed_nodes == NULL) {
414  n_data->allowed_nodes = rsc->allowed_nodes;
415  }
416 
417  if (rsc->children) {
418  GList *gIter = rsc->children;
419 
420  for (; gIter != NULL; gIter = gIter->next) {
421  pe_resource_t *child = (pe_resource_t *) gIter->data;
422 
423  collect_notification_data(child, state, activity, n_data);
424  }
425  return;
426  }
427 
428  if (state) {
429  notify_entry_t *entry = NULL;
430 
431  entry = calloc(1, sizeof(notify_entry_t));
432  entry->rsc = rsc;
433  if (rsc->running_on) {
434  /* we only take the first one */
435  entry->node = rsc->running_on->data;
436  }
437 
438  pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(rsc->role));
439 
440  switch (rsc->role) {
441  case RSC_ROLE_STOPPED:
442  n_data->inactive = g_list_prepend(n_data->inactive, entry);
443  break;
444  case RSC_ROLE_STARTED:
445  n_data->active = g_list_prepend(n_data->active, entry);
446  break;
447  case RSC_ROLE_UNPROMOTED:
448  n_data->unpromoted = g_list_prepend(n_data->unpromoted, entry);
449  n_data->active = g_list_prepend(n_data->active,
450  dup_notify_entry(entry));
451  break;
452  case RSC_ROLE_PROMOTED:
453  n_data->promoted = g_list_prepend(n_data->promoted, entry);
454  n_data->active = g_list_prepend(n_data->active,
455  dup_notify_entry(entry));
456  break;
457  default:
458  crm_err("Unsupported notify role");
459  free(entry);
460  break;
461  }
462  }
463 
464  if (activity) {
465  notify_entry_t *entry = NULL;
466  enum action_tasks task;
467 
468  GList *gIter = rsc->actions;
469 
470  for (; gIter != NULL; gIter = gIter->next) {
471  pe_action_t *op = (pe_action_t *) gIter->data;
472 
474  && (op->node != NULL)) {
475 
476  task = text2task(op->task);
477 
478  if(task == stop_rsc && op->node->details->unclean) {
479  // Create anyway (additional noise if node can't be fenced)
480  } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
481  continue;
482  }
483 
484  entry = calloc(1, sizeof(notify_entry_t));
485  entry->node = op->node;
486  entry->rsc = rsc;
487 
488  switch (task) {
489  case start_rsc:
490  n_data->start = g_list_prepend(n_data->start, entry);
491  break;
492  case stop_rsc:
493  n_data->stop = g_list_prepend(n_data->stop, entry);
494  break;
495  case action_promote:
496  n_data->promote = g_list_prepend(n_data->promote, entry);
497  break;
498  case action_demote:
499  n_data->demote = g_list_prepend(n_data->demote, entry);
500  break;
501  default:
502  free(entry);
503  break;
504  }
505  }
506  }
507  }
508 }
509 
510 #define add_notify_env(n_data, key, value) do { \
511  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
512  } while (0)
513 
514 #define add_notify_env_free(n_data, key, value) do { \
515  n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value); \
516  free(value); value = NULL; \
517  } while (0)
518 
527 void
529  notify_data_t *n_data,
530  pe_working_set_t *data_set)
531 {
532  bool required = false; // Whether to make notify actions required
533  char *rsc_list = NULL;
534  char *node_list = NULL;
535  char *metal_list = NULL;
536  const char *source = NULL;
537  GList *nodes = NULL;
538 
539  n_data->stop = expand_list(n_data->stop, &rsc_list, &node_list);
540  if (!pcmk__str_eq(" ", rsc_list, pcmk__str_null_matches)
541  && pcmk__str_eq(n_data->action, RSC_STOP, pcmk__str_casei)) {
542  required = true;
543  }
544  add_notify_env_free(n_data, "notify_stop_resource", rsc_list);
545  add_notify_env_free(n_data, "notify_stop_uname", node_list);
546 
547  if ((n_data->start != NULL)
548  && pcmk__str_eq(n_data->action, RSC_START, pcmk__str_casei)) {
549  required = true;
550  }
551  n_data->start = expand_list(n_data->start, &rsc_list, &node_list);
552  add_notify_env_free(n_data, "notify_start_resource", rsc_list);
553  add_notify_env_free(n_data, "notify_start_uname", node_list);
554 
555  if ((n_data->demote != NULL)
556  && pcmk__str_eq(n_data->action, RSC_DEMOTE, pcmk__str_casei)) {
557  required = true;
558  }
559  n_data->demote = expand_list(n_data->demote, &rsc_list, &node_list);
560  add_notify_env_free(n_data, "notify_demote_resource", rsc_list);
561  add_notify_env_free(n_data, "notify_demote_uname", node_list);
562 
563  if ((n_data->promote != NULL)
564  && pcmk__str_eq(n_data->action, RSC_PROMOTE, pcmk__str_casei)) {
565  required = true;
566  }
567  n_data->promote = expand_list(n_data->promote, &rsc_list, &node_list);
568  add_notify_env_free(n_data, "notify_promote_resource", rsc_list);
569  add_notify_env_free(n_data, "notify_promote_uname", node_list);
570 
571  n_data->active = expand_list(n_data->active, &rsc_list, &node_list);
572  add_notify_env_free(n_data, "notify_active_resource", rsc_list);
573  add_notify_env_free(n_data, "notify_active_uname", node_list);
574 
575  n_data->unpromoted = expand_list(n_data->unpromoted, &rsc_list, &node_list);
576  add_notify_env(n_data, "notify_unpromoted_resource", rsc_list);
577  add_notify_env(n_data, "notify_unpromoted_uname", node_list);
578 
579  // Deprecated: kept for backward compatibility with older resource agents
580  add_notify_env_free(n_data, "notify_slave_resource", rsc_list);
581  add_notify_env_free(n_data, "notify_slave_uname", node_list);
582 
583  n_data->promoted = expand_list(n_data->promoted, &rsc_list, &node_list);
584  add_notify_env(n_data, "notify_promoted_resource", rsc_list);
585  add_notify_env(n_data, "notify_promoted_uname", node_list);
586 
587  // Deprecated: kept for backward compatibility with older resource agents
588  add_notify_env_free(n_data, "notify_master_resource", rsc_list);
589  add_notify_env_free(n_data, "notify_master_uname", node_list);
590 
591  n_data->inactive = expand_list(n_data->inactive, &rsc_list, NULL);
592  add_notify_env_free(n_data, "notify_inactive_resource", rsc_list);
593 
594  nodes = g_hash_table_get_values(n_data->allowed_nodes);
595  if (!pcmk__is_daemon) {
596  /* If printing to stdout, sort the node list, for consistent
597  * regression test output (while avoiding the performance hit
598  * for the live cluster).
599  */
600  nodes = g_list_sort(nodes, sort_node_uname);
601  }
602  expand_node_list(nodes, &node_list, NULL);
603  add_notify_env_free(n_data, "notify_available_uname", node_list);
604  g_list_free(nodes);
605 
606  source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
607  if (pcmk__str_eq("host", source, pcmk__str_casei)) {
608  expand_node_list(data_set->nodes, &node_list, &metal_list);
609  add_notify_env_free(n_data, "notify_all_hosts", metal_list);
610  } else {
611  expand_node_list(data_set->nodes, &node_list, NULL);
612  }
613  add_notify_env_free(n_data, "notify_all_uname", node_list);
614 
615  if (required && n_data->pre) {
617  __func__, __LINE__);
619  __func__, __LINE__);
620  }
621 
622  if (required && n_data->post) {
624  __func__, __LINE__);
626  __func__, __LINE__);
627  }
628 }
629 
630 /*
631  * \internal
632  * \brief Find any remote connection start relevant to an action
633  *
634  * \param[in] action Action to chek
635  *
636  * \return If action is behind a remote connection, connection's start
637  */
638 static pe_action_t *
639 find_remote_start(pe_action_t *action)
640 {
641  if (action && action->node) {
642  pe_resource_t *remote_rsc = action->node->details->remote_rsc;
643 
644  if (remote_rsc) {
645  return find_first_action(remote_rsc->actions, NULL, RSC_START,
646  NULL);
647  }
648  }
649  return NULL;
650 }
651 
652 void
654 {
655  GList *gIter = NULL;
656  pe_action_t *stop = NULL;
657  pe_action_t *start = NULL;
658  enum action_tasks task = text2task(n_data->action);
659 
660  if (rsc->children) {
661  gIter = rsc->children;
662  for (; gIter != NULL; gIter = gIter->next) {
663  pe_resource_t *child = (pe_resource_t *) gIter->data;
664 
665  create_notifications(child, n_data, data_set);
666  }
667  return;
668  }
669 
670  /* Copy notification details into standard ops */
671 
672  for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
673  pe_action_t *op = (pe_action_t *) gIter->data;
674 
676  && (op->node != NULL)) {
677 
678  enum action_tasks t = text2task(op->task);
679 
680  switch (t) {
681  case start_rsc:
682  case stop_rsc:
683  case action_promote:
684  case action_demote:
685  add_notify_data_to_action_meta(n_data, op);
686  break;
687  default:
688  break;
689  }
690  }
691  }
692 
693  switch (task) {
694  case start_rsc:
695  if (n_data->start == NULL) {
696  pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
697  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
698  return;
699  }
700  break;
701  case action_promote:
702  if (n_data->promote == NULL) {
703  pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
704  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
705  return;
706  }
707  break;
708  case action_demote:
709  if (n_data->demote == NULL) {
710  pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
711  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
712  return;
713  }
714  break;
715  default:
716  /* We cannot do the same for stop_rsc/n_data->stop at it
717  * might be implied by fencing
718  */
719  break;
720  }
721 
722  pe_rsc_trace(rsc, "Creating notifications for: %s.%s (%s->%s)",
723  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
724 
725  stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
726  start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
727 
728  /* stop / demote */
729  if (rsc->role != RSC_ROLE_STOPPED) {
730  if (task == stop_rsc || task == action_demote) {
731  gIter = rsc->running_on;
732  for (; gIter != NULL; gIter = gIter->next) {
733  pe_node_t *current_node = (pe_node_t *) gIter->data;
734 
735  /* if this stop action is a pseudo action as a result of the current
736  * node being fenced, this stop action is implied by the fencing
737  * action. There's no reason to send the fenced node a stop notification */
738  if (stop && pcmk_is_set(stop->flags, pe_action_pseudo) &&
739  (current_node->details->unclean || current_node->details->remote_requires_reset) ) {
740 
741  continue;
742  }
743 
744  pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set);
745  if (task == action_demote || stop == NULL
746  || pcmk_is_set(stop->flags, pe_action_optional)) {
747  pe_post_notify(rsc, current_node, n_data, data_set);
748  }
749  }
750  }
751  }
752 
753  /* start / promote */
754  if (rsc->next_role != RSC_ROLE_STOPPED) {
755  if (rsc->allocated_to == NULL) {
756  pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role),
757  rsc->id);
758 
759  } else if (task == start_rsc || task == action_promote) {
760 
761  if (start) {
762  pe_action_t *remote_start = find_remote_start(start);
763 
764  if (remote_start
765  && !pcmk_is_set(remote_start->flags, pe_action_runnable)) {
766  /* Start and promote actions for a clone instance behind
767  * a Pacemaker Remote connection happen after the
768  * connection starts. If the connection start is blocked, do
769  * not schedule notifications for these actions.
770  */
771  return;
772  }
773  }
774  if ((task != start_rsc) || (start == NULL)
775  || pcmk_is_set(start->flags, pe_action_optional)) {
776 
777  pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set);
778  }
779  pe_post_notify(rsc, rsc->allocated_to, n_data, data_set);
780  }
781  }
782 }
783 
784 void
786 {
787  if (n_data == NULL) {
788  return;
789  }
790 
791  g_list_free_full(n_data->stop, free);
792  g_list_free_full(n_data->start, free);
793  g_list_free_full(n_data->demote, free);
794  g_list_free_full(n_data->promote, free);
795  g_list_free_full(n_data->promoted, free);
796  g_list_free_full(n_data->unpromoted, free);
797  g_list_free_full(n_data->active, free);
798  g_list_free_full(n_data->inactive, free);
799  pcmk_free_nvpairs(n_data->keys);
800  free(n_data);
801 }
802 
803 void
805  pe_action_t *stonith_op,
806  pe_working_set_t *data_set)
807 {
808  notify_data_t *n_data;
809 
810  crm_info("Creating secondary notification for %s", action->uuid);
811  n_data = create_notification_boundaries(rsc, RSC_STOP, NULL, stonith_op,
812  data_set);
813  collect_notification_data(rsc, TRUE, FALSE, n_data);
814  add_notify_env(n_data, "notify_stop_resource", rsc->id);
815  add_notify_env(n_data, "notify_stop_uname", action->node->details->uname);
816  create_notifications(uber_parent(rsc), n_data, data_set);
817  free_notification_data(n_data);
818 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
void pcmk__create_notification_keys(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
#define RSC_STOP
Definition: crm.h:204
char * name
Definition: nvpair.h:29
#define INFINITY
Definition: crm.h:99
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:103
GHashTable * allowed_nodes
Definition: internal.h:209
int priority
Definition: pe_types.h:407
pe_resource_t * container
Definition: pe_types.h:379
char * value
Definition: nvpair.h:30
GList * start
Definition: internal.h:203
enum rsc_role_e role
Definition: pe_types.h:369
#define RSC_NOTIFIED
Definition: crm.h:213
GList * children
Definition: pe_types.h:376
void collect_notification_data(pe_resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data)
enum rsc_role_e next_role
Definition: pe_types.h:370
pe_resource_t * remote_rsc
Definition: pe_types.h:230
GHashTable * meta
Definition: pe_types.h:372
#define pe_rsc_notify
Definition: pe_types.h:253
void create_notifications(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
enum action_tasks text2task(const char *task)
Definition: common.c:354
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:202
#define RSC_START
Definition: crm.h:201
pe_node_t * allocated_to
Definition: pe_types.h:362
GList * inactive
Definition: internal.h:202
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:221
#define pe_proc_err(fmt...)
Definition: internal.h:32
gboolean remote_requires_reset
Definition: pe_types.h:224
#define RSC_NOTIFY
Definition: crm.h:212
const char * action
Definition: pcmk_fence.c:30
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 free_notification_data(notify_data_t *n_data)
GList * nodes
Definition: pe_types.h:157
const char * role2text(enum rsc_role_e role)
Definition: common.c:459
GList * active
Definition: internal.h:201
GList * stop
Definition: internal.h:204
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:229
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:903
pe_action_t * post
Definition: internal.h:197
#define add_notify_env_free(n_data, key, value)
char * task
Definition: pe_types.h:413
GList * promote
Definition: internal.h:206
GHashTable * meta
Definition: pe_types.h:423
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
struct pe_node_shared_s * details
Definition: pe_types.h:244
pe_node_t * node
Definition: pe_types.h:410
bool pcmk__is_daemon
Definition: logging.c:47
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1802
unsigned long long flags
Definition: pe_types.h:347
const char * uname
Definition: pe_types.h:209
GList * actions
Definition: pe_types.h:358
GSList * keys
Definition: internal.h:192
char * uuid
Definition: pe_types.h:414
gboolean update_action_flags(pe_action_t *action, enum pe_action_flags flags, const char *source, int line)
GList * promoted
Definition: internal.h:207
pe_action_t * post_done
Definition: internal.h:199
struct notify_entry_s notify_entry_t
GList * unpromoted
Definition: internal.h:208
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:579
#define crm_err(fmt, args...)
Definition: logging.h:350
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_PROMOTE
Definition: crm.h:207
#define add_notify_env(n_data, key, value)
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:295
char uname[MAX_NAME]
Definition: cpg.c:50
GList * demote
Definition: internal.h:205
GList * running_on
Definition: pe_types.h:365
enum pe_action_flags flags
Definition: pe_types.h:418
#define RSC_CANCEL
Definition: crm.h:196
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:20
const char * action
Definition: internal.h:194
gint sort_node_uname(gconstpointer a, gconstpointer b)
Definition: utils.c:218
gboolean unclean
Definition: pe_types.h:217
#define crm_info(fmt, args...)
Definition: logging.h:353
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1422
pe_action_t * pre_done
Definition: internal.h:198
gboolean online
Definition: pe_types.h:213
action_tasks
Definition: common.h:62
pe_action_t * pre
Definition: internal.h:196
#define RSC_DEMOTE
Definition: crm.h:209
void create_secondary_notification(pe_action_t *action, pe_resource_t *rsc, pe_action_t *stonith_op, pe_working_set_t *data_set)
char * id
Definition: pe_types.h:320
GHashTable * allowed_nodes
Definition: pe_types.h:367
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