pacemaker  2.1.4-dc6eb4362
Scalable High-Availability cluster resource manager
pcmk_sched_bundle.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2022 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 
12 #include <stdbool.h>
13 
14 #include <crm/msg_xml.h>
15 #include <pacemaker-internal.h>
16 
17 #include "libpacemaker_private.h"
18 
19 #define PE__VARIANT_BUNDLE 1
20 #include <lib/pengine/variant.h>
21 
22 static bool
23 is_bundle_node(pe__bundle_variant_data_t *data, pe_node_t *node)
24 {
25  for (GList *gIter = data->replicas; gIter != NULL; gIter = gIter->next) {
26  pe__bundle_replica_t *replica = gIter->data;
27 
28  if (node->details == replica->node->details) {
29  return TRUE;
30  }
31  }
32  return FALSE;
33 }
34 
35 gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
36 void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
37  int max, int per_host_max, pe_working_set_t * data_set);
38 
39 static GList *
40 get_container_list(pe_resource_t *rsc)
41 {
42  GList *containers = NULL;
43 
44  if (rsc->variant == pe_container) {
45  pe__bundle_variant_data_t *data = NULL;
46 
47  get_bundle_variant_data(data, rsc);
48  for (GList *gIter = data->replicas; gIter != NULL;
49  gIter = gIter->next) {
50  pe__bundle_replica_t *replica = gIter->data;
51 
52  containers = g_list_append(containers, replica->container);
53  }
54  }
55  return containers;
56 }
57 
58 static inline GList *
59 get_containers_or_children(pe_resource_t *rsc)
60 {
61  return (rsc->variant == pe_container)?
62  get_container_list(rsc) : rsc->children;
63 }
64 
65 pe_node_t *
68 {
69  GList *containers = NULL;
70  GList *nodes = NULL;
71  pe__bundle_variant_data_t *bundle_data = NULL;
72 
73  CRM_CHECK(rsc != NULL, return NULL);
74 
75  get_bundle_variant_data(bundle_data, rsc);
76 
78  containers = get_container_list(rsc);
79 
81  rsc, __func__, rsc->allowed_nodes, data_set);
82 
83  nodes = g_hash_table_get_values(rsc->allowed_nodes);
84  nodes = pcmk__sort_nodes(nodes, NULL, data_set);
85  containers = g_list_sort_with_data(containers, sort_clone_instance, data_set);
86  distribute_children(rsc, containers, nodes, bundle_data->nreplicas,
87  bundle_data->nreplicas_per_host, data_set);
88  g_list_free(nodes);
89  g_list_free(containers);
90 
91  for (GList *gIter = bundle_data->replicas; gIter != NULL;
92  gIter = gIter->next) {
93  pe__bundle_replica_t *replica = gIter->data;
94  pe_node_t *container_host = NULL;
95 
96  CRM_ASSERT(replica);
97  if (replica->ip) {
98  pe_rsc_trace(rsc, "Allocating bundle %s IP %s",
99  rsc->id, replica->ip->id);
100  replica->ip->cmds->allocate(replica->ip, prefer, data_set);
101  }
102 
103  container_host = replica->container->allocated_to;
104  if (replica->remote && pe__is_guest_or_remote_node(container_host)) {
105  /* We need 'nested' connection resources to be on the same
106  * host because pacemaker-remoted only supports a single
107  * active connection
108  */
109  pcmk__new_colocation("child-remote-with-docker-remote", NULL,
110  INFINITY, replica->remote,
111  container_host->details->remote_rsc, NULL,
112  NULL, true, data_set);
113  }
114 
115  if (replica->remote) {
116  pe_rsc_trace(rsc, "Allocating bundle %s connection %s",
117  rsc->id, replica->remote->id);
118  replica->remote->cmds->allocate(replica->remote, prefer,
119  data_set);
120  }
121 
122  // Explicitly allocate replicas' children before bundle child
123  if (replica->child) {
124  pe_node_t *node = NULL;
125  GHashTableIter iter;
126 
127  g_hash_table_iter_init(&iter, replica->child->allowed_nodes);
128  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
129  if (node->details != replica->node->details) {
130  node->weight = -INFINITY;
131  } else if (!pcmk__threshold_reached(replica->child, node,
132  NULL)) {
133  node->weight = INFINITY;
134  }
135  }
136 
137  pe__set_resource_flags(replica->child->parent, pe_rsc_allocating);
138  pe_rsc_trace(rsc, "Allocating bundle %s replica child %s",
139  rsc->id, replica->child->id);
140  replica->child->cmds->allocate(replica->child, replica->node,
141  data_set);
142  pe__clear_resource_flags(replica->child->parent,
144  }
145  }
146 
147  if (bundle_data->child) {
148  pe_node_t *node = NULL;
149  GHashTableIter iter;
150  g_hash_table_iter_init(&iter, bundle_data->child->allowed_nodes);
151  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
152  if (is_bundle_node(bundle_data, node)) {
153  node->weight = 0;
154  } else {
155  node->weight = -INFINITY;
156  }
157  }
158  pe_rsc_trace(rsc, "Allocating bundle %s child %s",
159  rsc->id, bundle_data->child->id);
160  bundle_data->child->cmds->allocate(bundle_data->child, prefer, data_set);
161  }
162 
164  return NULL;
165 }
166 
167 
168 void
170 {
171  pe_action_t *action = NULL;
172  GList *containers = NULL;
173  pe__bundle_variant_data_t *bundle_data = NULL;
174 
175  CRM_CHECK(rsc != NULL, return);
176 
177  containers = get_container_list(rsc);
178  get_bundle_variant_data(bundle_data, rsc);
179  for (GList *gIter = bundle_data->replicas; gIter != NULL;
180  gIter = gIter->next) {
181  pe__bundle_replica_t *replica = gIter->data;
182 
183  CRM_ASSERT(replica);
184  if (replica->ip) {
185  replica->ip->cmds->create_actions(replica->ip, data_set);
186  }
187  if (replica->container) {
188  replica->container->cmds->create_actions(replica->container,
189  data_set);
190  }
191  if (replica->remote) {
192  replica->remote->cmds->create_actions(replica->remote, data_set);
193  }
194  }
195 
196  clone_create_pseudo_actions(rsc, containers, NULL, NULL, data_set);
197 
198  if (bundle_data->child) {
199  bundle_data->child->cmds->create_actions(bundle_data->child, data_set);
200 
201  if (pcmk_is_set(bundle_data->child->flags, pe_rsc_promotable)) {
202  /* promote */
203  pcmk__new_rsc_pseudo_action(rsc, RSC_PROMOTE, true, true);
204  action = pcmk__new_rsc_pseudo_action(rsc, RSC_PROMOTED, true, true);
205  action->priority = INFINITY;
206 
207  /* demote */
208  pcmk__new_rsc_pseudo_action(rsc, RSC_DEMOTE, true, true);
209  action = pcmk__new_rsc_pseudo_action(rsc, RSC_DEMOTED, true, true);
210  action->priority = INFINITY;
211  }
212  }
213 
214  g_list_free(containers);
215 }
216 
217 void
220 {
221  pe__bundle_variant_data_t *bundle_data = NULL;
222 
223  CRM_CHECK(rsc != NULL, return);
224 
225  get_bundle_variant_data(bundle_data, rsc);
226 
227  if (bundle_data->child) {
228  pcmk__order_resource_actions(rsc, RSC_START, bundle_data->child,
230  data_set);
231  pcmk__order_resource_actions(rsc, RSC_STOP, bundle_data->child,
233  data_set);
234 
235  if (bundle_data->child->children) {
236  pcmk__order_resource_actions(bundle_data->child, RSC_STARTED, rsc,
237  RSC_STARTED,
239  data_set);
240  pcmk__order_resource_actions(bundle_data->child, RSC_STOPPED, rsc,
241  RSC_STOPPED,
243  data_set);
244  } else {
245  pcmk__order_resource_actions(bundle_data->child, RSC_START, rsc,
246  RSC_STARTED,
248  data_set);
249  pcmk__order_resource_actions(bundle_data->child, RSC_STOP, rsc,
250  RSC_STOPPED,
252  data_set);
253  }
254  }
255 
256  for (GList *gIter = bundle_data->replicas; gIter != NULL;
257  gIter = gIter->next) {
258  pe__bundle_replica_t *replica = gIter->data;
259 
260  CRM_ASSERT(replica);
261  CRM_ASSERT(replica->container);
262 
263  replica->container->cmds->internal_constraints(replica->container,
264  data_set);
265 
266  pcmk__order_starts(rsc, replica->container,
268  data_set);
269 
270  if (replica->child) {
271  pcmk__order_stops(rsc, replica->child,
273  }
274  pcmk__order_stops(rsc, replica->container,
276  pcmk__order_resource_actions(replica->container, RSC_START, rsc,
278  data_set);
279  pcmk__order_resource_actions(replica->container, RSC_STOP, rsc,
281  data_set);
282 
283  if (replica->ip) {
284  replica->ip->cmds->internal_constraints(replica->ip, data_set);
285 
286  // Start IP then container
287  pcmk__order_starts(replica->ip, replica->container,
289  data_set);
290  pcmk__order_stops(replica->container, replica->ip,
292  data_set);
293 
294  pcmk__new_colocation("ip-with-docker", NULL, INFINITY, replica->ip,
295  replica->container, NULL, NULL, true,
296  data_set);
297  }
298 
299  if (replica->remote) {
300  /* This handles ordering and colocating remote relative to container
301  * (via "resource-with-container"). Since IP is also ordered and
302  * colocated relative to the container, we don't need to do anything
303  * explicit here with IP.
304  */
305  replica->remote->cmds->internal_constraints(replica->remote,
306  data_set);
307  }
308 
309  if (replica->child) {
310  CRM_ASSERT(replica->remote);
311 
312  // "Start remote then child" is implicit in scheduler's remote logic
313  }
314 
315  }
316 
317  if (bundle_data->child) {
318  bundle_data->child->cmds->internal_constraints(bundle_data->child, data_set);
319  if (pcmk_is_set(bundle_data->child->flags, pe_rsc_promotable)) {
321 
322  /* child demoted before global demoted */
323  pcmk__order_resource_actions(bundle_data->child, RSC_DEMOTED, rsc,
324  RSC_DEMOTED,
326  data_set);
327 
328  /* global demote before child demote */
329  pcmk__order_resource_actions(rsc, RSC_DEMOTE, bundle_data->child,
330  RSC_DEMOTE,
332  data_set);
333 
334  /* child promoted before global promoted */
335  pcmk__order_resource_actions(bundle_data->child, RSC_PROMOTED, rsc,
336  RSC_PROMOTED,
338  data_set);
339 
340  /* global promote before child promote */
341  pcmk__order_resource_actions(rsc, RSC_PROMOTE, bundle_data->child,
342  RSC_PROMOTE,
344  data_set);
345  }
346  }
347 }
348 
349 static pe_resource_t *
350 compatible_replica_for_node(pe_resource_t *rsc_lh, pe_node_t *candidate,
351  pe_resource_t *rsc, enum rsc_role_e filter,
352  gboolean current)
353 {
354  pe__bundle_variant_data_t *bundle_data = NULL;
355 
356  CRM_CHECK(candidate != NULL, return NULL);
357  get_bundle_variant_data(bundle_data, rsc);
358 
359  crm_trace("Looking for compatible child from %s for %s on %s",
360  rsc_lh->id, rsc->id, candidate->details->uname);
361 
362  for (GList *gIter = bundle_data->replicas; gIter != NULL;
363  gIter = gIter->next) {
364  pe__bundle_replica_t *replica = gIter->data;
365 
366  if (is_child_compatible(replica->container, candidate, filter, current)) {
367  crm_trace("Pairing %s with %s on %s",
368  rsc_lh->id, replica->container->id,
369  candidate->details->uname);
370  return replica->container;
371  }
372  }
373 
374  crm_trace("Can't pair %s with %s", rsc_lh->id, rsc->id);
375  return NULL;
376 }
377 
378 static pe_resource_t *
379 compatible_replica(pe_resource_t *rsc_lh, pe_resource_t *rsc,
380  enum rsc_role_e filter, gboolean current,
382 {
383  GList *scratch = NULL;
384  pe_resource_t *pair = NULL;
385  pe_node_t *active_node_lh = NULL;
386 
387  active_node_lh = rsc_lh->fns->location(rsc_lh, NULL, current);
388  if (active_node_lh) {
389  return compatible_replica_for_node(rsc_lh, active_node_lh, rsc, filter,
390  current);
391  }
392 
393  scratch = g_hash_table_get_values(rsc_lh->allowed_nodes);
394  scratch = pcmk__sort_nodes(scratch, NULL, data_set);
395 
396  for (GList *gIter = scratch; gIter != NULL; gIter = gIter->next) {
397  pe_node_t *node = (pe_node_t *) gIter->data;
398 
399  pair = compatible_replica_for_node(rsc_lh, node, rsc, filter, current);
400  if (pair) {
401  goto done;
402  }
403  }
404 
405  pe_rsc_debug(rsc, "Can't pair %s with %s", rsc_lh->id, (rsc? rsc->id : "none"));
406  done:
407  g_list_free(scratch);
408  return pair;
409 }
410 
411 void
413  pcmk__colocation_t *constraint,
415 {
416  /* -- Never called --
417  *
418  * Instead we add the colocation constraints to the child and call from there
419  */
420  CRM_ASSERT(FALSE);
421 }
422 
424 {
425  /* Strictly speaking, there should be a 'copies_per_node' addition
426  * to the resource function table and each case would be a
427  * function. However that would be serious overkill to return an
428  * int. In fact, it seems to me that both function tables
429  * could/should be replaced by resources.{c,h} full of
430  * rsc_{some_operation} functions containing a switch as below
431  * which calls out to functions named {variant}_{some_operation}
432  * as needed.
433  */
434  switch(rsc->variant) {
435  case pe_unknown:
436  return 0;
437  case pe_native:
438  case pe_group:
439  return 1;
440  case pe_clone:
441  {
442  const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
443 
444  if (max_clones_node == NULL) {
445  return 1;
446 
447  } else {
448  int max_i;
449 
450  pcmk__scan_min_int(max_clones_node, &max_i, 0);
451  return max_i;
452  }
453  }
454  case pe_container:
455  {
456  pe__bundle_variant_data_t *data = NULL;
457  get_bundle_variant_data(data, rsc);
458  return data->nreplicas_per_host;
459  }
460  }
461  return 0;
462 }
463 
464 void
466  pcmk__colocation_t *constraint,
468 {
469  GList *allocated_primaries = NULL;
470  pe__bundle_variant_data_t *bundle_data = NULL;
471 
472  CRM_CHECK(constraint != NULL, return);
473  CRM_CHECK(dependent != NULL,
474  pe_err("dependent was NULL for %s", constraint->id); return);
475  CRM_CHECK(primary != NULL,
476  pe_err("primary was NULL for %s", constraint->id); return);
477  CRM_ASSERT(dependent->variant == pe_native);
478 
479  if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
480  pe_rsc_trace(primary, "%s is still provisional", primary->id);
481  return;
482 
483  } else if(constraint->dependent->variant > pe_group) {
484  pe_resource_t *primary_replica = compatible_replica(dependent, primary,
486  FALSE, data_set);
487 
488  if (primary_replica) {
489  pe_rsc_debug(primary, "Pairing %s with %s",
490  dependent->id, primary_replica->id);
491  dependent->cmds->rsc_colocation_lh(dependent, primary_replica,
492  constraint, data_set);
493 
494  } else if (constraint->score >= INFINITY) {
495  crm_notice("Cannot pair %s with instance of %s",
496  dependent->id, primary->id);
497  pcmk__assign_resource(dependent, NULL, true);
498 
499  } else {
500  pe_rsc_debug(primary, "Cannot pair %s with instance of %s",
501  dependent->id, primary->id);
502  }
503 
504  return;
505  }
506 
507  get_bundle_variant_data(bundle_data, primary);
508  pe_rsc_trace(primary, "Processing constraint %s: %s -> %s %d",
509  constraint->id, dependent->id, primary->id, constraint->score);
510 
511  for (GList *gIter = bundle_data->replicas; gIter != NULL;
512  gIter = gIter->next) {
513  pe__bundle_replica_t *replica = gIter->data;
514 
515  if (constraint->score < INFINITY) {
516  replica->container->cmds->rsc_colocation_rh(dependent,
517  replica->container,
518  constraint, data_set);
519 
520  } else {
521  pe_node_t *chosen = replica->container->fns->location(replica->container,
522  NULL, FALSE);
523 
524  if ((chosen == NULL)
525  || is_set_recursive(replica->container, pe_rsc_block, TRUE)) {
526  continue;
527  }
528  if ((constraint->primary_role >= RSC_ROLE_PROMOTED)
529  && (replica->child == NULL)) {
530  continue;
531  }
532  if ((constraint->primary_role >= RSC_ROLE_PROMOTED)
533  && (replica->child->next_role < RSC_ROLE_PROMOTED)) {
534  continue;
535  }
536 
537  pe_rsc_trace(primary, "Allowing %s: %s %d",
538  constraint->id, chosen->details->uname,
539  chosen->weight);
540  allocated_primaries = g_list_prepend(allocated_primaries, chosen);
541  }
542  }
543 
544  if (constraint->score >= INFINITY) {
545  node_list_exclude(dependent->allowed_nodes, allocated_primaries, FALSE);
546  }
547  g_list_free(allocated_primaries);
548 }
549 
550 enum pe_action_flags
552 {
553  GList *containers = NULL;
554  enum pe_action_flags flags = 0;
555  pe__bundle_variant_data_t *data = NULL;
556 
557  get_bundle_variant_data(data, action->rsc);
558  if(data->child) {
559  enum action_tasks task = get_complex_task(data->child, action->task, TRUE);
560  switch(task) {
561  case no_action:
562  case action_notify:
563  case action_notified:
564  case action_promote:
565  case action_promoted:
566  case action_demote:
567  case action_demoted:
568  return summary_action_flags(action, data->child->children, node);
569  default:
570  break;
571  }
572  }
573 
574  containers = get_container_list(action->rsc);
575  flags = summary_action_flags(action, containers, node);
576  g_list_free(containers);
577  return flags;
578 }
579 
582  enum rsc_role_e filter, gboolean current)
583 {
584  GList *gIter = NULL;
585  GList *children = NULL;
586 
587  if (local_node == NULL) {
588  crm_err("Can't colocate unrunnable child %s with %s", local_child->id, rsc->id);
589  return NULL;
590  }
591 
592  crm_trace("Looking for compatible child from %s for %s on %s",
593  local_child->id, rsc->id, local_node->details->uname);
594 
595  children = get_containers_or_children(rsc);
596  for (gIter = children; gIter != NULL; gIter = gIter->next) {
597  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
598 
599  if(is_child_compatible(child_rsc, local_node, filter, current)) {
600  crm_trace("Pairing %s with %s on %s",
601  local_child->id, child_rsc->id, local_node->details->uname);
602  return child_rsc;
603  }
604  }
605 
606  crm_trace("Can't pair %s with %s", local_child->id, rsc->id);
607  if(children != rsc->children) {
608  g_list_free(children);
609  }
610  return NULL;
611 }
612 
613 static pe__bundle_replica_t *
614 replica_for_container(pe_resource_t *rsc, pe_resource_t *container,
615  pe_node_t *node)
616 {
617  if (rsc->variant == pe_container) {
618  pe__bundle_variant_data_t *data = NULL;
619 
620  get_bundle_variant_data(data, rsc);
621  for (GList *gIter = data->replicas; gIter != NULL;
622  gIter = gIter->next) {
623  pe__bundle_replica_t *replica = gIter->data;
624 
625  if (replica->child
626  && (container == replica->container)
627  && (node->details == replica->node->details)) {
628  return replica;
629  }
630  }
631  }
632  return NULL;
633 }
634 
635 static enum pe_graph_flags
636 multi_update_interleave_actions(pe_action_t *first, pe_action_t *then,
637  pe_node_t *node, enum pe_action_flags flags,
638  enum pe_action_flags filter,
639  enum pe_ordering type,
641 {
642  GList *gIter = NULL;
643  GList *children = NULL;
644  gboolean current = FALSE;
645  enum pe_graph_flags changed = pe_graph_none;
646 
647  /* Fix this - lazy */
648  if (pcmk__ends_with(first->uuid, "_stopped_0")
649  || pcmk__ends_with(first->uuid, "_demoted_0")) {
650  current = TRUE;
651  }
652 
653  children = get_containers_or_children(then->rsc);
654  for (gIter = children; gIter != NULL; gIter = gIter->next) {
655  pe_resource_t *then_child = gIter->data;
656  pe_resource_t *first_child = find_compatible_child(then_child,
657  first->rsc,
659  current, data_set);
660  if (first_child == NULL && current) {
661  crm_trace("Ignore");
662 
663  } else if (first_child == NULL) {
664  crm_debug("No match found for %s (%d / %s / %s)", then_child->id, current, first->uuid, then->uuid);
665 
666  /* Me no like this hack - but what else can we do?
667  *
668  * If there is no-one active or about to be active
669  * on the same node as then_child, then they must
670  * not be allowed to start
671  */
672  if (type & (pe_order_runnable_left | pe_order_implies_then) /* Mandatory */ ) {
673  pe_rsc_info(then->rsc, "Inhibiting %s from being active", then_child->id);
674  if (pcmk__assign_resource(then_child, NULL, true)) {
676  }
677  }
678 
679  } else {
680  pe_action_t *first_action = NULL;
681  pe_action_t *then_action = NULL;
682 
683  enum action_tasks task = clone_child_action(first);
684  const char *first_task = task2text(task);
685 
686  pe__bundle_replica_t *first_replica = NULL;
687  pe__bundle_replica_t *then_replica = NULL;
688 
689  first_replica = replica_for_container(first->rsc, first_child,
690  node);
691  if (strstr(first->task, "stop") && first_replica && first_replica->child) {
692  /* Except for 'stopped' we should be looking at the
693  * in-container resource, actions for the child will
694  * happen later and are therefor more likely to align
695  * with the user's intent.
696  */
697  first_action = find_first_action(first_replica->child->actions,
698  NULL, task2text(task), node);
699  } else {
700  first_action = find_first_action(first_child->actions, NULL, task2text(task), node);
701  }
702 
703  then_replica = replica_for_container(then->rsc, then_child, node);
704  if (strstr(then->task, "mote")
705  && then_replica && then_replica->child) {
706  /* Promote/demote actions will never be found for the
707  * container resource, look in the child instead
708  *
709  * Alternatively treat:
710  * 'XXXX then promote YYYY' as 'XXXX then start container for YYYY', and
711  * 'demote XXXX then stop YYYY' as 'stop container for XXXX then stop YYYY'
712  */
713  then_action = find_first_action(then_replica->child->actions,
714  NULL, then->task, node);
715  } else {
716  then_action = find_first_action(then_child->actions, NULL, then->task, node);
717  }
718 
719  if (first_action == NULL) {
720  if (!pcmk_is_set(first_child->flags, pe_rsc_orphan)
721  && !pcmk__str_any_of(first_task, RSC_STOP, RSC_DEMOTE, NULL)) {
722  crm_err("Internal error: No action found for %s in %s (first)",
723  first_task, first_child->id);
724 
725  } else {
726  crm_trace("No action found for %s in %s%s (first)",
727  first_task, first_child->id,
728  pcmk_is_set(first_child->flags, pe_rsc_orphan)? " (ORPHAN)" : "");
729  }
730  continue;
731  }
732 
733  /* We're only interested if 'then' is neither stopping nor being demoted */
734  if (then_action == NULL) {
735  if (!pcmk_is_set(then_child->flags, pe_rsc_orphan)
736  && !pcmk__str_any_of(then->task, RSC_STOP, RSC_DEMOTE, NULL)) {
737  crm_err("Internal error: No action found for %s in %s (then)",
738  then->task, then_child->id);
739 
740  } else {
741  crm_trace("No action found for %s in %s%s (then)",
742  then->task, then_child->id,
743  pcmk_is_set(then_child->flags, pe_rsc_orphan)? " (ORPHAN)" : "");
744  }
745  continue;
746  }
747 
748  if (order_actions(first_action, then_action, type)) {
749  crm_debug("Created constraint for %s (%d) -> %s (%d) %.6x",
750  first_action->uuid,
751  pcmk_is_set(first_action->flags, pe_action_optional),
752  then_action->uuid,
753  pcmk_is_set(then_action->flags, pe_action_optional),
754  type);
755  pe__set_graph_flags(changed, first,
757  }
758  if(first_action && then_action) {
759  changed |= then_child->cmds->update_actions(first_action,
760  then_action, node,
761  first_child->cmds->action_flags(first_action, node),
762  filter, type, data_set);
763  } else {
764  crm_err("Nothing found either for %s (%p) or %s (%p) %s",
765  first_child->id, first_action,
766  then_child->id, then_action, task2text(task));
767  }
768  }
769  }
770 
771  if(children != then->rsc->children) {
772  g_list_free(children);
773  }
774  return changed;
775 }
776 
777 static bool
778 can_interleave_actions(pe_action_t *first, pe_action_t *then)
779 {
780  bool interleave = FALSE;
781  pe_resource_t *rsc = NULL;
782  const char *interleave_s = NULL;
783 
784  if(first->rsc == NULL || then->rsc == NULL) {
785  crm_trace("Not interleaving %s with %s (both must be resources)", first->uuid, then->uuid);
786  return FALSE;
787  } else if(first->rsc == then->rsc) {
788  crm_trace("Not interleaving %s with %s (must belong to different resources)", first->uuid, then->uuid);
789  return FALSE;
790  } else if(first->rsc->variant < pe_clone || then->rsc->variant < pe_clone) {
791  crm_trace("Not interleaving %s with %s (both sides must be clones or bundles)", first->uuid, then->uuid);
792  return FALSE;
793  }
794 
795  if (pcmk__ends_with(then->uuid, "_stop_0")
796  || pcmk__ends_with(then->uuid, "_demote_0")) {
797  rsc = first->rsc;
798  } else {
799  rsc = then->rsc;
800  }
801 
802  interleave_s = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERLEAVE);
803  interleave = crm_is_true(interleave_s);
804  crm_trace("Interleave %s -> %s: %s (based on %s)",
805  first->uuid, then->uuid, interleave ? "yes" : "no", rsc->id);
806 
807  return interleave;
808 }
809 
810 enum pe_graph_flags
812  pe_node_t *node, enum pe_action_flags flags,
813  enum pe_action_flags filter, enum pe_ordering type,
815 {
816  enum pe_graph_flags changed = pe_graph_none;
817 
818  crm_trace("%s -> %s", first->uuid, then->uuid);
819 
820  if(can_interleave_actions(first, then)) {
821  changed = multi_update_interleave_actions(first, then, node, flags,
822  filter, type, data_set);
823 
824  } else if(then->rsc) {
825  GList *gIter = NULL;
826  GList *children = NULL;
827 
828  // Handle the 'primitive' ordering case
829  changed |= native_update_actions(first, then, node, flags, filter,
830  type, data_set);
831 
832  // Now any children (or containers in the case of a bundle)
833  children = get_containers_or_children(then->rsc);
834  for (gIter = children; gIter != NULL; gIter = gIter->next) {
835  pe_resource_t *then_child = (pe_resource_t *) gIter->data;
836  enum pe_graph_flags then_child_changed = pe_graph_none;
837  pe_action_t *then_child_action = find_first_action(then_child->actions, NULL, then->task, node);
838 
839  if (then_child_action) {
840  enum pe_action_flags then_child_flags = then_child->cmds->action_flags(then_child_action, node);
841 
842  if (pcmk_is_set(then_child_flags, pe_action_runnable)) {
843  then_child_changed |= then_child->cmds->update_actions(first,
844  then_child_action, node, flags, filter, type, data_set);
845  }
846  changed |= then_child_changed;
847  if (then_child_changed & pe_graph_updated_then) {
848  for (GList *lpc = then_child_action->actions_after; lpc != NULL; lpc = lpc->next) {
849  pe_action_wrapper_t *next = (pe_action_wrapper_t *) lpc->data;
850 
852  data_set);
853  }
854  }
855  }
856  }
857 
858  if(children != then->rsc->children) {
859  g_list_free(children);
860  }
861  }
862  return changed;
863 }
864 
865 void
867 {
868  pe__bundle_variant_data_t *bundle_data = NULL;
869  get_bundle_variant_data(bundle_data, rsc);
870 
871  pcmk__apply_location(constraint, rsc);
872 
873  for (GList *gIter = bundle_data->replicas; gIter != NULL;
874  gIter = gIter->next) {
875  pe__bundle_replica_t *replica = gIter->data;
876 
877  if (replica->container) {
878  replica->container->cmds->rsc_location(replica->container,
879  constraint);
880  }
881  if (replica->ip) {
882  replica->ip->cmds->rsc_location(replica->ip, constraint);
883  }
884  }
885 
886  if (bundle_data->child
887  && ((constraint->role_filter == RSC_ROLE_UNPROMOTED)
888  || (constraint->role_filter == RSC_ROLE_PROMOTED))) {
889  bundle_data->child->cmds->rsc_location(bundle_data->child, constraint);
890  bundle_data->child->rsc_location = g_list_prepend(bundle_data->child->rsc_location,
891  constraint);
892  }
893 }
894 
895 void
897 {
898  pe__bundle_variant_data_t *bundle_data = NULL;
899 
900  CRM_CHECK(rsc != NULL, return);
901 
902  get_bundle_variant_data(bundle_data, rsc);
903 
904  if (bundle_data->child) {
905  bundle_data->child->cmds->expand(bundle_data->child, data_set);
906  }
907 
908  for (GList *gIter = bundle_data->replicas; gIter != NULL;
909  gIter = gIter->next) {
910  pe__bundle_replica_t *replica = gIter->data;
911 
912  CRM_ASSERT(replica);
913  if (replica->remote && replica->container
914  && pe__bundle_needs_remote_name(replica->remote, data_set)) {
915 
916  /* REMOTE_CONTAINER_HACK: Allow remote nodes to run containers that
917  * run pacemaker-remoted inside, without needing a separate IP for
918  * the container. This is done by configuring the inner remote's
919  * connection host as the magic string "#uname", then
920  * replacing it with the underlying host when needed.
921  */
922  xmlNode *nvpair = get_xpath_object("//nvpair[@name='" XML_RSC_ATTR_REMOTE_RA_ADDR "']",
923  replica->remote->xml, LOG_ERR);
924  const char *calculated_addr = NULL;
925 
926  // Replace the value in replica->remote->xml (if appropriate)
927  calculated_addr = pe__add_bundle_remote_name(replica->remote,
928  data_set,
929  nvpair, "value");
930  if (calculated_addr) {
931  /* Since this is for the bundle as a resource, and not any
932  * particular action, replace the value in the default
933  * parameters (not evaluated for node). create_graph_action()
934  * will grab it from there to replace it in node-evaluated
935  * parameters.
936  */
937  GHashTable *params = pe_rsc_params(replica->remote,
938  NULL, data_set);
939 
940  crm_trace("Set address for bundle connection %s to bundle host %s",
941  replica->remote->id, calculated_addr);
942  g_hash_table_replace(params,
944  strdup(calculated_addr));
945  } else {
946  /* The only way to get here is if the remote connection is
947  * neither currently running nor scheduled to run. That means we
948  * won't be doing any operations that require addr (only start
949  * requires it; we additionally use it to compare digests when
950  * unpacking status, promote, and migrate_from history, but
951  * that's already happened by this point).
952  */
953  crm_info("Unable to determine address for bundle %s remote connection",
954  rsc->id);
955  }
956  }
957  if (replica->ip) {
958  replica->ip->cmds->expand(replica->ip, data_set);
959  }
960  if (replica->container) {
961  replica->container->cmds->expand(replica->container, data_set);
962  }
963  if (replica->remote) {
964  replica->remote->cmds->expand(replica->remote, data_set);
965  }
966  }
967 }
968 
969 gboolean
971  pe_action_t *complete, gboolean force,
973 {
974  bool any_created = FALSE;
975  pe__bundle_variant_data_t *bundle_data = NULL;
976 
977  CRM_CHECK(rsc != NULL, return FALSE);
978 
979  get_bundle_variant_data(bundle_data, rsc);
980  for (GList *gIter = bundle_data->replicas; gIter != NULL;
981  gIter = gIter->next) {
982  pe__bundle_replica_t *replica = gIter->data;
983 
984  CRM_ASSERT(replica);
985  if (replica->ip) {
986  any_created |= replica->ip->cmds->create_probe(replica->ip, node,
987  complete, force,
988  data_set);
989  }
990  if (replica->child && (node->details == replica->node->details)) {
991  any_created |= replica->child->cmds->create_probe(replica->child,
992  node, complete,
993  force, data_set);
994  }
995  if (replica->container) {
996  bool created = replica->container->cmds->create_probe(replica->container,
997  node, complete,
998  force, data_set);
999 
1000  if(created) {
1001  any_created = TRUE;
1002  /* If we're limited to one replica per host (due to
1003  * the lack of an IP range probably), then we don't
1004  * want any of our peer containers starting until
1005  * we've established that no other copies are already
1006  * running.
1007  *
1008  * Partly this is to ensure that nreplicas_per_host is
1009  * observed, but also to ensure that the containers
1010  * don't fail to start because the necessary port
1011  * mappings (which won't include an IP for uniqueness)
1012  * are already taken
1013  */
1014 
1015  for (GList *tIter = bundle_data->replicas;
1016  tIter && (bundle_data->nreplicas_per_host == 1);
1017  tIter = tIter->next) {
1018  pe__bundle_replica_t *other = tIter->data;
1019 
1020  if ((other != replica) && (other != NULL)
1021  && (other->container != NULL)) {
1022 
1023  pcmk__new_ordering(replica->container,
1024  pcmk__op_key(replica->container->id, RSC_STATUS, 0),
1025  NULL, other->container,
1026  pcmk__op_key(other->container->id, RSC_START, 0),
1027  NULL,
1029  data_set);
1030  }
1031  }
1032  }
1033  }
1034  if (replica->container && replica->remote
1035  && replica->remote->cmds->create_probe(replica->remote, node,
1036  complete, force,
1037  data_set)) {
1038 
1039  /* Do not probe the remote resource until we know where the
1040  * container is running. This is required for REMOTE_CONTAINER_HACK
1041  * to correctly probe remote resources.
1042  */
1043  char *probe_uuid = pcmk__op_key(replica->remote->id, RSC_STATUS,
1044  0);
1045  pe_action_t *probe = find_first_action(replica->remote->actions,
1046  probe_uuid, NULL, node);
1047 
1048  free(probe_uuid);
1049  if (probe) {
1050  any_created = TRUE;
1051  crm_trace("Ordering %s probe on %s",
1052  replica->remote->id, node->details->uname);
1053  pcmk__new_ordering(replica->container,
1054  pcmk__op_key(replica->container->id, RSC_START, 0),
1055  NULL, replica->remote, NULL, probe,
1057  }
1058  }
1059  }
1060  return any_created;
1061 }
1062 
1063 void
1065 {
1066 }
1067 
1068 void
1070 {
1071  pe__bundle_variant_data_t *bundle_data = NULL;
1072 
1073  CRM_CHECK(rsc != NULL, return);
1074 
1075  get_bundle_variant_data(bundle_data, rsc);
1076  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1077  gIter = gIter->next) {
1078  pe__bundle_replica_t *replica = gIter->data;
1079 
1080  CRM_ASSERT(replica);
1081  if (replica->ip != NULL) {
1082  replica->ip->cmds->output_actions(replica->ip);
1083  }
1084  if (replica->container != NULL) {
1085  replica->container->cmds->output_actions(replica->container);
1086  }
1087  if (replica->remote != NULL) {
1088  replica->remote->cmds->output_actions(replica->remote);
1089  }
1090  if (replica->child != NULL) {
1091  replica->child->cmds->output_actions(replica->child);
1092  }
1093  }
1094 }
1095 
1096 // Bundle implementation of resource_alloc_functions_t:add_utilization()
1097 void
1099  GList *all_rscs, GHashTable *utilization)
1100 {
1101  pe__bundle_variant_data_t *bundle_data = NULL;
1102  pe__bundle_replica_t *replica = NULL;
1103 
1104  if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
1105  return;
1106  }
1107 
1108  get_bundle_variant_data(bundle_data, rsc);
1109  if (bundle_data->replicas == NULL) {
1110  return;
1111  }
1112 
1113  /* All bundle replicas are identical, so using the utilization of the first
1114  * is sufficient for any. Only the implicit container resource can have
1115  * utilization values.
1116  */
1117  replica = (pe__bundle_replica_t *) bundle_data->replicas->data;
1118  if (replica->container != NULL) {
1119  replica->container->cmds->add_utilization(replica->container, orig_rsc,
1120  all_rscs, utilization);
1121  }
1122 }
1123 
1124 // Bundle implementation of resource_alloc_functions_t:shutdown_lock()
1125 void
1127 {
1128  return; // Bundles currently don't support shutdown locks
1129 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
pe_node_t * pcmk__bundle_allocate(pe_resource_t *rsc, pe_node_t *prefer, pe_working_set_t *data_set)
enum rsc_role_e role_filter
Definition: internal.h:174
const char * task2text(enum action_tasks task)
Definition: common.c:401
void pcmk__output_bundle_actions(pe_resource_t *rsc)
void pcmk__bundle_add_utilization(pe_resource_t *rsc, pe_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
#define RSC_STOP
Definition: crm.h:204
bool is_set_recursive(pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:448
#define crm_notice(fmt, args...)
Definition: logging.h:360
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition: remote.c:41
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:21
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:99
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:355
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
#define pcmk__order_starts(rsc1, rsc2, type, data_set)
pe_resource_t * container
Definition: pe_types.h:394
GList * children
Definition: pe_types.h:391
resource_alloc_functions_t * cmds
Definition: pe_types.h:348
G_GNUC_INTERNAL void pcmk__new_ordering(pe_resource_t *lh_rsc, char *lh_task, pe_action_t *lh_action, pe_resource_t *rh_rsc, char *rh_task, pe_action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set)
enum pe_graph_flags(* update_actions)(pe_action_t *, pe_action_t *, pe_node_t *, enum pe_action_flags, enum pe_action_flags, enum pe_ordering, pe_working_set_t *data_set)
G_GNUC_INTERNAL bool pcmk__threshold_reached(pe_resource_t *rsc, pe_node_t *node, pe_resource_t **failed)
pe_resource_t * rsc
Definition: pe_types.h:424
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
void pcmk__bundle_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
pe_resource_t * remote_rsc
Definition: pe_types.h:237
GHashTable * meta
Definition: pe_types.h:387
resource_object_functions_t * fns
Definition: pe_types.h:347
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, pe_node_t *node)
bool pe__bundle_needs_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: bundle.c:943
pe_resource_t * dependent
enum pe_graph_flags pcmk__multi_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type, pe_working_set_t *data_set)
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:160
#define pcmk__order_stops(rsc1, rsc2, type, data_set)
enum pe_graph_flags native_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type, pe_working_set_t *data_set)
enum crm_ais_msg_types type
Definition: cpg.c:48
gboolean pcmk__bundle_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
enum pe_action_flags pcmk__bundle_action_flags(pe_action_t *action, pe_node_t *node)
#define RSC_START
Definition: crm.h:201
pe_action_t * action
Definition: pe_types.h:548
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:536
gboolean is_child_compatible(pe_resource_t *child_rsc, pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
#define XML_RSC_ATTR_REMOTE_RA_ADDR
Definition: msg_xml.h:253
const char * action
Definition: pcmk_fence.c:29
G_GNUC_INTERNAL void pcmk__new_colocation(const char *id, const char *node_attr, int score, pe_resource_t *dependent, pe_resource_t *primary, const char *dependent_role, const char *primary_role, bool influence, pe_working_set_t *data_set)
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:49
void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes, int max, int per_host_max, pe_working_set_t *data_set)
#define pe_rsc_provisional
Definition: pe_types.h:266
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55
int weight
Definition: pe_types.h:249
pe_action_flags
Definition: pe_types.h:305
#define crm_debug(fmt, args...)
Definition: logging.h:363
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
void pcmk__bundle_rsc_colocation_lh(pe_resource_t *dependent, pe_resource_t *primary, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
pe_resource_t * find_compatible_child_by_node(pe_resource_t *local_child, pe_node_t *local_node, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
void(* rsc_colocation_lh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
char * task
Definition: pe_types.h:428
#define crm_trace(fmt, args...)
Definition: logging.h:364
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1518
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:122
void promote_demote_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
struct pe_node_shared_s * details
Definition: pe_types.h:252
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1906
unsigned long long flags
Definition: pe_types.h:362
const char * uname
Definition: pe_types.h:216
#define pe_rsc_promotable
Definition: pe_types.h:264
GHashTable * pe_rsc_params(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:457
pe_working_set_t * data_set
#define pcmk__order_resource_actions(lh_rsc, lh_task, rh_rsc, rh_task, flags, data_set)
enum action_tasks clone_child_action(pe_action_t *action)
#define pe__set_graph_flags(graph_flags, gr_action, flags_to_set)
Definition: internal.h:127
GList * actions
Definition: pe_types.h:373
pe_graph_flags
Definition: pe_types.h:297
void pcmk__bundle_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:234
char * uuid
Definition: pe_types.h:429
enum pe_action_flags(* action_flags)(pe_action_t *, pe_node_t *)
#define pe_rsc_allocating
Definition: pe_types.h:267
enum pe_obj_types variant
Definition: pe_types.h:345
void pcmk__bundle_shutdown_lock(pe_resource_t *rsc)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:955
#define RSC_DEMOTED
Definition: crm.h:210
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:45
const char * pe__add_bundle_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set, xmlNode *xml, const char *field)
Definition: bundle.c:961
void clone_create_pseudo_actions(pe_resource_t *rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify, pe_working_set_t *data_set)
pe_resource_t * find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current, pe_working_set_t *data_set)
G_GNUC_INTERNAL pe_action_t * pcmk__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
void pcmk__bundle_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
G_GNUC_INTERNAL void pcmk__update_action_for_orderings(pe_action_t *action, pe_working_set_t *data_set)
#define RSC_STARTED
Definition: crm.h:202
int copies_per_node(pe_resource_t *rsc)
#define crm_err(fmt, args...)
Definition: logging.h:358
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:215
#define RSC_PROMOTE
Definition: crm.h:207
G_GNUC_INTERNAL bool pcmk__assign_resource(pe_resource_t *rsc, pe_node_t *node, bool force)
void pcmk__bundle_append_meta(pe_resource_t *rsc, xmlNode *xml)
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:55
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
#define pe_rsc_block
Definition: pe_types.h:258
enum pe_action_flags flags
Definition: pe_types.h:433
#define RSC_STOPPED
Definition: crm.h:205
void pcmk__bundle_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
#define RSC_PROMOTED
Definition: crm.h:208
gboolean crm_is_true(const char *s)
Definition: strings.c:416
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:22
unsigned long long flags
Definition: pe_types.h:153
#define pe_err(fmt...)
Definition: internal.h:24
#define XML_RSC_ATTR_INTERLEAVE
Definition: msg_xml.h:230
void pcmk__bundle_rsc_colocation_rh(pe_resource_t *dependent, pe_resource_t *primary, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
#define pe_flag_show_scores
Definition: pe_types.h:134
#define crm_info(fmt, args...)
Definition: logging.h:361
#define pe_rsc_orphan
Definition: pe_types.h:256
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1541
pe_ordering
Definition: pe_types.h:497
G_GNUC_INTERNAL void pcmk__apply_location(pe__location_t *constraint, pe_resource_t *rsc)
uint64_t flags
Definition: remote.c:149
action_tasks
Definition: common.h:61
#define RSC_DEMOTE
Definition: crm.h:209
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:20
char * id
Definition: pe_types.h:336
GHashTable * allowed_nodes
Definition: pe_types.h:382