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