pacemaker  2.1.2-ada5c3b36
Scalable High-Availability cluster resource manager
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 
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 
341  order_actions(n_data->pre_done, start, pe_order_optional);
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;
354  if (pcmk_is_set(end->flags, pe_action_runnable)) {
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;
374  if (pcmk_is_set(end->flags, pe_action_runnable)) {
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 
396 void
397 collect_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;
435  case RSC_ROLE_UNPROMOTED:
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;
440  case RSC_ROLE_PROMOTED:
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 
515 void
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  */
622 static pe_action_t *
623 find_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 
636 void
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
730  || pcmk_is_set(stop->flags, pe_action_optional)) {
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)
759  || pcmk_is_set(start->flags, pe_action_optional)) {
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 
768 void
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 
787 void
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);
801  free_notification_data(n_data);
802 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:225
#define RSC_STOP
Definition: crm.h:204
char * name
Definition: nvpair.h:29
#define INFINITY
Definition: crm.h:99
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:59
void pcmk_free_nvpairs(GSList *nvpairs)
Free a list of name/value pairs.
Definition: nvpair.c:102
GHashTable * allowed_nodes
Definition: internal.h:209
bool pcmk__is_daemon
Definition: logging.c:47
int priority
Definition: pe_types.h:408
pe_resource_t * container
Definition: pe_types.h:380
char * value
Definition: nvpair.h:30
GList * start
Definition: internal.h:203
enum rsc_role_e role
Definition: pe_types.h:370
#define RSC_NOTIFIED
Definition: crm.h:213
GList * children
Definition: pe_types.h:377
enum rsc_role_e next_role
Definition: pe_types.h:371
pe_resource_t * remote_rsc
Definition: pe_types.h:230
GHashTable * meta
Definition: pe_types.h:373
#define pe_rsc_notify
Definition: pe_types.h:253
enum action_tasks text2task(const char *task)
Definition: common.c:354
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:209
#define RSC_START
Definition: crm.h:201
pe_node_t * allocated_to
Definition: pe_types.h:363
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
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
void pcmk__create_notification_keys(pe_resource_t *rsc, notify_data_t *n_data, pe_working_set_t *data_set)
pe_action_t * post
Definition: internal.h:197
#define add_notify_env_free(n_data, key, value)
char * task
Definition: pe_types.h:414
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:68
GList * promote
Definition: internal.h:206
GHashTable * meta
Definition: pe_types.h:424
#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:411
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1905
unsigned long long flags
Definition: pe_types.h:348
const char * uname
Definition: pe_types.h:209
GList * actions
Definition: pe_types.h:359
GSList * keys
Definition: internal.h:192
char * uuid
Definition: pe_types.h:415
GList * promoted
Definition: internal.h:207
pe_action_t * post_done
Definition: internal.h:199
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)
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:357
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_PROMOTE
Definition: crm.h:207
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)
#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:366
enum pe_action_flags flags
Definition: pe_types.h:419
#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:360
void free_notification_data(notify_data_t *n_data)
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1540
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
void collect_notification_data(pe_resource_t *rsc, gboolean state, gboolean activity, notify_data_t *n_data)
#define RSC_DEMOTE
Definition: crm.h:209
char * id
Definition: pe_types.h:322
GHashTable * allowed_nodes
Definition: pe_types.h:368
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:731
void create_secondary_notification(pe_action_t *action, pe_resource_t *rsc, pe_action_t *stonith_op, pe_working_set_t *data_set)