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