pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
pcmk_sched_bundle.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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/common/xml.h>
15 #include <pacemaker-internal.h>
16 
17 #include "libpacemaker_private.h"
18 
19 struct assign_data {
20  const pcmk_node_t *prefer;
21  bool stop_if_fail;
22 };
23 
33 static bool
34 assign_replica(pcmk__bundle_replica_t *replica, void *user_data)
35 {
36  pcmk_node_t *container_host = NULL;
37 
38  struct assign_data *assign_data = user_data;
39  const pcmk_node_t *prefer = assign_data->prefer;
40  bool stop_if_fail = assign_data->stop_if_fail;
41 
42  const pcmk_resource_t *bundle = pe__const_top_resource(replica->container,
43  true);
44 
45  if (replica->ip != NULL) {
46  pcmk__rsc_trace(bundle, "Assigning bundle %s IP %s",
47  bundle->id, replica->ip->id);
48  replica->ip->priv->cmds->assign(replica->ip, prefer, stop_if_fail);
49  }
50 
51  container_host = replica->container->priv->assigned_node;
52  if (replica->remote != NULL) {
53  if (pcmk__is_pacemaker_remote_node(container_host)) {
54  /* REMOTE_CONTAINER_HACK: "Nested" connection resources must be on
55  * the same host because Pacemaker Remote only supports a single
56  * active connection.
57  */
58  pcmk__new_colocation("#replica-remote-with-host-remote", NULL,
59  PCMK_SCORE_INFINITY, replica->remote,
60  container_host->priv->remote, NULL,
61  NULL, pcmk__coloc_influence);
62  }
63  pcmk__rsc_trace(bundle, "Assigning bundle %s connection %s",
64  bundle->id, replica->remote->id);
65  replica->remote->priv->cmds->assign(replica->remote, prefer,
66  stop_if_fail);
67  }
68 
69  if (replica->child != NULL) {
70  pcmk_node_t *node = NULL;
71  GHashTableIter iter;
72 
73  g_hash_table_iter_init(&iter, replica->child->priv->allowed_nodes);
74  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
75  if (!pcmk__same_node(node, replica->node)) {
76  node->assign->score = -PCMK_SCORE_INFINITY;
77  } else if (!pcmk__threshold_reached(replica->child, node, NULL)) {
78  node->assign->score = PCMK_SCORE_INFINITY;
79  }
80  }
81 
84  pcmk__rsc_trace(bundle, "Assigning bundle %s replica child %s",
85  bundle->id, replica->child->id);
86  replica->child->priv->cmds->assign(replica->child, replica->node,
87  stop_if_fail);
90  }
91  return true;
92 }
93 
113 pcmk_node_t *
115  bool stop_if_fail)
116 {
117  GList *containers = NULL;
118  pcmk_resource_t *bundled_resource = NULL;
119  struct assign_data assign_data = { prefer, stop_if_fail };
120 
121  pcmk__assert(pcmk__is_bundle(rsc));
122 
123  pcmk__rsc_trace(rsc, "Assigning bundle %s", rsc->id);
125 
128  rsc, __func__, rsc->priv->allowed_nodes,
129  rsc->priv->scheduler);
130 
131  // Assign all containers first, so we know what nodes the bundle will be on
132  containers = g_list_sort(pe__bundle_containers(rsc), pcmk__cmp_instance);
133  pcmk__assign_instances(rsc, containers, pe__bundle_max(rsc),
134  rsc->priv->fns->max_per_node(rsc));
135  g_list_free(containers);
136 
137  // Then assign remaining replica resources
138  pe__foreach_bundle_replica(rsc, assign_replica, (void *) &assign_data);
139 
140  // Finally, assign the bundled resources to each bundle node
141  bundled_resource = pe__bundled_resource(rsc);
142  if (bundled_resource != NULL) {
143  pcmk_node_t *node = NULL;
144  GHashTableIter iter;
145 
146  g_hash_table_iter_init(&iter, bundled_resource->priv->allowed_nodes);
147  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
148  if (pe__node_is_bundle_instance(rsc, node)) {
149  node->assign->score = 0;
150  } else {
151  node->assign->score = -PCMK_SCORE_INFINITY;
152  }
153  }
154  bundled_resource->priv->cmds->assign(bundled_resource, prefer,
155  stop_if_fail);
156  }
157 
159  return NULL;
160 }
161 
171 static bool
172 create_replica_actions(pcmk__bundle_replica_t *replica, void *user_data)
173 {
174  if (replica->ip != NULL) {
175  replica->ip->priv->cmds->create_actions(replica->ip);
176  }
177  if (replica->container != NULL) {
178  replica->container->priv->cmds->create_actions(replica->container);
179  }
180  if (replica->remote != NULL) {
181  replica->remote->priv->cmds->create_actions(replica->remote);
182  }
183  return true;
184 }
185 
192 void
194 {
195  pcmk_action_t *action = NULL;
196  GList *containers = NULL;
197  pcmk_resource_t *bundled_resource = NULL;
198 
199  pcmk__assert(pcmk__is_bundle(rsc));
200 
201  pe__foreach_bundle_replica(rsc, create_replica_actions, NULL);
202 
203  containers = pe__bundle_containers(rsc);
204  pcmk__create_instance_actions(rsc, containers);
205  g_list_free(containers);
206 
207  bundled_resource = pe__bundled_resource(rsc);
208  if (bundled_resource != NULL) {
209  bundled_resource->priv->cmds->create_actions(bundled_resource);
210 
211  if (pcmk_is_set(bundled_resource->flags, pcmk__rsc_promotable)) {
214  true, true);
215  action->priority = PCMK_SCORE_INFINITY;
216 
219  true, true);
220  action->priority = PCMK_SCORE_INFINITY;
221  }
222  }
223 }
224 
234 static bool
235 replica_internal_constraints(pcmk__bundle_replica_t *replica, void *user_data)
236 {
237  pcmk_resource_t *bundle = user_data;
238 
239  replica->container->priv->cmds->internal_constraints(replica->container);
240 
241  // Start bundle -> start replica container
242  pcmk__order_starts(bundle, replica->container,
245 
246  // Stop bundle -> stop replica child and container
247  if (replica->child != NULL) {
248  pcmk__order_stops(bundle, replica->child,
250  }
251  pcmk__order_stops(bundle, replica->container,
253 
254  // Start replica container -> bundle is started
258 
259  // Stop replica container -> bundle is stopped
263 
264  if (replica->ip != NULL) {
265  replica->ip->priv->cmds->internal_constraints(replica->ip);
266 
267  // Replica IP address -> replica container (symmetric)
268  pcmk__order_starts(replica->ip, replica->container,
271  pcmk__order_stops(replica->container, replica->ip,
273 
274  pcmk__new_colocation("#ip-with-container", NULL, PCMK_SCORE_INFINITY,
275  replica->ip, replica->container, NULL, NULL,
277  }
278 
279  if (replica->remote != NULL) {
280  /* This handles ordering and colocating remote relative to container
281  * (via "#resource-with-container"). Since IP is also ordered and
282  * colocated relative to the container, we don't need to do anything
283  * explicit here with IP.
284  */
285  replica->remote->priv->cmds->internal_constraints(replica->remote);
286  }
287 
288  if (replica->child != NULL) {
289  pcmk__assert(replica->remote != NULL);
290  // "Start remote then child" is implicit in scheduler's remote logic
291  }
292  return true;
293 }
294 
301 void
303 {
304  pcmk_resource_t *bundled_resource = NULL;
305 
306  pcmk__assert(pcmk__is_bundle(rsc));
307 
308  pe__foreach_bundle_replica(rsc, replica_internal_constraints, rsc);
309 
310  bundled_resource = pe__bundled_resource(rsc);
311  if (bundled_resource == NULL) {
312  return;
313  }
314 
315  // Start bundle -> start bundled clone
316  pcmk__order_resource_actions(rsc, PCMK_ACTION_START, bundled_resource,
319 
320  // Bundled clone is started -> bundle is started
322  rsc, PCMK_ACTION_RUNNING,
324 
325  // Stop bundle -> stop bundled clone
326  pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP, bundled_resource,
329 
330  // Bundled clone is stopped -> bundle is stopped
332  rsc, PCMK_ACTION_STOPPED,
334 
335  bundled_resource->priv->cmds->internal_constraints(bundled_resource);
336 
337  if (!pcmk_is_set(bundled_resource->flags, pcmk__rsc_promotable)) {
338  return;
339  }
341 
342  // Demote bundle -> demote bundled clone
343  pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTE, bundled_resource,
346 
347  // Bundled clone is demoted -> bundle is demoted
349  rsc, PCMK_ACTION_DEMOTED,
351 
352  // Promote bundle -> promote bundled clone
354  bundled_resource, PCMK_ACTION_PROMOTE,
356 
357  // Bundled clone is promoted -> bundle is promoted
361 }
362 
363 struct match_data {
364  const pcmk_node_t *node; // Node to compare against replica
365  pcmk_resource_t *container; // Replica container corresponding to node
366 };
367 
378 static bool
379 match_replica_container(const pcmk__bundle_replica_t *replica, void *user_data)
380 {
381  struct match_data *match_data = user_data;
382 
383  if (pcmk__instance_matches(replica->container, match_data->node,
384  pcmk_role_unknown, false)) {
385  match_data->container = replica->container;
386  return false; // Match found, don't bother searching further replicas
387  }
388  return true; // No match, keep searching
389 }
390 
400 static const pcmk_node_t *
401 get_bundle_node_host(const pcmk_node_t *node)
402 {
403  if (pcmk__is_bundle_node(node)) {
404  const pcmk_resource_t *container = NULL;
405 
406  container = node->priv->remote->priv->launcher;
407  return container->priv->fns->location(container, NULL,
409  }
410  return node;
411 }
412 
424 static pcmk_resource_t *
425 compatible_container(const pcmk_resource_t *dependent,
426  const pcmk_resource_t *bundle)
427 {
428  GList *scratch = NULL;
429  struct match_data match_data = { NULL, NULL };
430 
431  // If dependent is assigned, only check there
432  match_data.node = dependent->priv->fns->location(dependent, NULL,
434  match_data.node = get_bundle_node_host(match_data.node);
435  if (match_data.node != NULL) {
436  pe__foreach_const_bundle_replica(bundle, match_replica_container,
437  &match_data);
438  return match_data.container;
439  }
440 
441  // Otherwise, check for any of the dependent's allowed nodes
442  scratch = g_hash_table_get_values(dependent->priv->allowed_nodes);
443  scratch = pcmk__sort_nodes(scratch, NULL);
444  for (const GList *iter = scratch; iter != NULL; iter = iter->next) {
445  match_data.node = iter->data;
446  match_data.node = get_bundle_node_host(match_data.node);
447  if (match_data.node == NULL) {
448  continue;
449  }
450 
451  pe__foreach_const_bundle_replica(bundle, match_replica_container,
452  &match_data);
453  if (match_data.container != NULL) {
454  break;
455  }
456  }
457  g_list_free(scratch);
458  return match_data.container;
459 }
460 
461 struct coloc_data {
462  const pcmk__colocation_t *colocation;
463  pcmk_resource_t *dependent;
464  GList *container_hosts;
465  int priority_delta;
466 };
467 
477 static bool
478 replica_apply_coloc_score(const pcmk__bundle_replica_t *replica,
479  void *user_data)
480 {
481  struct coloc_data *coloc_data = user_data;
482  pcmk_node_t *chosen = NULL;
483  pcmk_resource_t *container = replica->container;
484 
485  if (coloc_data->colocation->score < PCMK_SCORE_INFINITY) {
486  int priority_delta =
487  container->priv->cmds->apply_coloc_score(coloc_data->dependent,
488  container,
489  coloc_data->colocation,
490  false);
491 
492  coloc_data->priority_delta =
493  pcmk__add_scores(coloc_data->priority_delta, priority_delta);
494  return true;
495  }
496 
497  chosen = container->priv->fns->location(container, NULL,
499  if ((chosen == NULL)
500  || is_set_recursive(container, pcmk__rsc_blocked, true)) {
501  return true;
502  }
503 
504  if ((coloc_data->colocation->primary_role >= pcmk_role_promoted)
505  && ((replica->child == NULL)
506  || (replica->child->priv->next_role < pcmk_role_promoted))) {
507  return true;
508  }
509 
510  pcmk__rsc_trace(pe__const_top_resource(container, true),
511  "Allowing mandatory colocation %s using %s @%d",
512  coloc_data->colocation->id, pcmk__node_name(chosen),
513  chosen->assign->score);
514  coloc_data->container_hosts = g_list_prepend(coloc_data->container_hosts,
515  chosen);
516  return true;
517 }
518 
534 int
536  const pcmk_resource_t *primary,
537  const pcmk__colocation_t *colocation,
538  bool for_dependent)
539 {
540  struct coloc_data coloc_data = { colocation, dependent, NULL, 0 };
541 
542  /* This should never be called for the bundle itself as a dependent.
543  * Instead, we add its colocation constraints to its containers and bundled
544  * primitive and call the apply_coloc_score() method for them as dependents.
545  */
546  pcmk__assert(pcmk__is_bundle(primary) && pcmk__is_primitive(dependent)
547  && (colocation != NULL) && !for_dependent);
548 
549  if (pcmk_is_set(primary->flags, pcmk__rsc_unassigned)) {
550  pcmk__rsc_trace(primary,
551  "Skipping applying colocation %s "
552  "because %s is still provisional",
553  colocation->id, primary->id);
554  return 0;
555  }
556  pcmk__rsc_trace(primary, "Applying colocation %s (%s with %s at %s)",
557  colocation->id, dependent->id, primary->id,
558  pcmk_readable_score(colocation->score));
559 
560  /* If the constraint dependent is a clone or bundle, "dependent" here is one
561  * of its instances. Look for a compatible instance of this bundle.
562  */
563  if (colocation->dependent->priv->variant > pcmk__rsc_variant_group) {
564  const pcmk_resource_t *primary_container = NULL;
565 
566  primary_container = compatible_container(dependent, primary);
567  if (primary_container != NULL) { // Success, we found one
568  pcmk__rsc_debug(primary, "Pairing %s with %s",
569  dependent->id, primary_container->id);
570 
571  return dependent->priv->cmds->apply_coloc_score(dependent,
572  primary_container,
573  colocation, true);
574  }
575 
576  if (colocation->score >= PCMK_SCORE_INFINITY) {
577  // Failure, and it's fatal
578  crm_notice("%s cannot run because there is no compatible "
579  "instance of %s to colocate with",
580  dependent->id, primary->id);
581  pcmk__assign_resource(dependent, NULL, true, true);
582 
583  } else { // Failure, but we can ignore it
584  pcmk__rsc_debug(primary,
585  "%s cannot be colocated with any instance of %s",
586  dependent->id, primary->id);
587  }
588  return 0;
589  }
590 
591  pe__foreach_const_bundle_replica(primary, replica_apply_coloc_score,
592  &coloc_data);
593 
594  if (colocation->score >= PCMK_SCORE_INFINITY) {
595  pcmk__colocation_intersect_nodes(dependent, primary, colocation,
596  coloc_data.container_hosts, false);
597  }
598  g_list_free(coloc_data.container_hosts);
599  return coloc_data.priority_delta;
600 }
601 
602 // Bundle implementation of pcmk__assignment_methods_t:with_this_colocations()
603 void
605  const pcmk_resource_t *orig_rsc, GList **list)
606 {
607  const pcmk_resource_t *bundled_rsc = NULL;
608 
609  pcmk__assert(pcmk__is_bundle(rsc) && (orig_rsc != NULL) && (list != NULL));
610 
611  // The bundle itself and its containers always get its colocations
612  if ((orig_rsc == rsc)
614 
616  orig_rsc);
617  return;
618  }
619 
620  /* The bundled resource gets the colocations if it's promotable and we've
621  * begun choosing roles
622  */
623  bundled_rsc = pe__bundled_resource(rsc);
624  if ((bundled_rsc == NULL)
625  || !pcmk_is_set(bundled_rsc->flags, pcmk__rsc_promotable)
626  || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
627  return;
628  }
629 
630  if (orig_rsc == bundled_rsc) {
631  if (pe__clone_flag_is_set(orig_rsc,
633  /* orig_rsc is the clone and we're setting roles (or have already
634  * done so)
635  */
637  orig_rsc);
638  }
639 
640  } else if (!pcmk_is_set(orig_rsc->flags, pcmk__rsc_unassigned)) {
641  /* orig_rsc is an instance and is already assigned. If something
642  * requests colocations for orig_rsc now, it's for setting roles.
643  */
645  orig_rsc);
646  }
647 }
648 
649 // Bundle implementation of pcmk__assignment_methods_t:this_with_colocations()
650 void
652  const pcmk_resource_t *orig_rsc, GList **list)
653 {
654  const pcmk_resource_t *bundled_rsc = NULL;
655 
656  pcmk__assert(pcmk__is_bundle(rsc) && (orig_rsc != NULL) && (list != NULL));
657 
658  // The bundle itself and its containers always get its colocations
659  if ((orig_rsc == rsc)
661 
663  orig_rsc);
664  return;
665  }
666 
667  /* The bundled resource gets the colocations if it's promotable and we've
668  * begun choosing roles
669  */
670  bundled_rsc = pe__bundled_resource(rsc);
671  if ((bundled_rsc == NULL)
672  || !pcmk_is_set(bundled_rsc->flags, pcmk__rsc_promotable)
673  || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
674  return;
675  }
676 
677  if (orig_rsc == bundled_rsc) {
678  if (pe__clone_flag_is_set(orig_rsc,
680  /* orig_rsc is the clone and we're setting roles (or have already
681  * done so)
682  */
684  orig_rsc);
685  }
686 
687  } else if (!pcmk_is_set(orig_rsc->flags, pcmk__rsc_unassigned)) {
688  /* orig_rsc is an instance and is already assigned. If something
689  * requests colocations for orig_rsc now, it's for setting roles.
690  */
692  orig_rsc);
693  }
694 }
695 
705 uint32_t
707 {
708  GList *containers = NULL;
709  uint32_t flags = 0;
710  pcmk_resource_t *bundled_resource = NULL;
711 
712  pcmk__assert((action != NULL) && pcmk__is_bundle(action->rsc));
713 
714  bundled_resource = pe__bundled_resource(action->rsc);
715  if (bundled_resource != NULL) {
716  GList *children = bundled_resource->priv->children;
717 
718  // Clone actions are done on the bundled clone resource, not container
719  switch (get_complex_task(bundled_resource, action->task)) {
721  case pcmk__action_notify:
725  case pcmk__action_demote:
727  return pcmk__collective_action_flags(action, children, node);
728  default:
729  break;
730  }
731  }
732 
733  containers = pe__bundle_containers(action->rsc);
734  flags = pcmk__collective_action_flags(action, containers, node);
735  g_list_free(containers);
736  return flags;
737 }
738 
748 static bool
749 apply_location_to_replica(pcmk__bundle_replica_t *replica, void *user_data)
750 {
751  pcmk__location_t *location = user_data;
752 
753  replica->container->priv->cmds->apply_location(replica->container,
754  location);
755  if (replica->ip != NULL) {
756  replica->ip->priv->cmds->apply_location(replica->ip, location);
757  }
758  return true;
759 }
760 
768 void
770 {
771  pcmk_resource_t *bundled_resource = NULL;
772 
773  pcmk__assert((location != NULL) && pcmk__is_bundle(rsc));
774 
775  pcmk__apply_location(rsc, location);
776  pe__foreach_bundle_replica(rsc, apply_location_to_replica, location);
777 
778  bundled_resource = pe__bundled_resource(rsc);
779  if ((bundled_resource != NULL)
780  && ((location->role_filter == pcmk_role_unpromoted)
781  || (location->role_filter == pcmk_role_promoted))) {
782 
783  bundled_resource->priv->cmds->apply_location(bundled_resource,
784  location);
785  bundled_resource->priv->location_constraints =
786  g_list_prepend(bundled_resource->priv->location_constraints,
787  location);
788  }
789 }
790 
791 #define XPATH_REMOTE "//nvpair[@name='" PCMK_REMOTE_RA_ADDR "']"
792 
802 static bool
803 add_replica_actions_to_graph(pcmk__bundle_replica_t *replica, void *user_data)
804 {
805  if ((replica->remote != NULL)
806  && pe__bundle_needs_remote_name(replica->remote)) {
807 
808  /* REMOTE_CONTAINER_HACK: Allow remote nodes to run containers that
809  * run the remote executor inside, without needing a separate IP for
810  * the container. This is done by configuring the inner remote's
811  * connection host as the magic string "#uname", then
812  * replacing it with the underlying host when needed.
813  */
814  xmlNode *nvpair = get_xpath_object(XPATH_REMOTE,
815  replica->remote->priv->xml, LOG_ERR);
816  const char *calculated_addr = NULL;
817 
818  // Replace the value in replica->remote->xml (if appropriate)
819  calculated_addr = pe__add_bundle_remote_name(replica->remote, nvpair,
820  PCMK_XA_VALUE);
821  if (calculated_addr != NULL) {
822  /* Since this is for the bundle as a resource, and not any
823  * particular action, replace the value in the default
824  * parameters (not evaluated for node). create_graph_action()
825  * will grab it from there to replace it in node-evaluated
826  * parameters.
827  */
828  GHashTable *params = NULL;
829 
830  params = pe_rsc_params(replica->remote, NULL,
831  replica->remote->priv->scheduler);
832  pcmk__insert_dup(params, PCMK_REMOTE_RA_ADDR, calculated_addr);
833  } else {
834  pcmk_resource_t *bundle = user_data;
835 
836  /* The only way to get here is if the remote connection is
837  * neither currently running nor scheduled to run. That means we
838  * won't be doing any operations that require addr (only start
839  * requires it; we additionally use it to compare digests when
840  * unpacking status, promote, and migrate_from history, but
841  * that's already happened by this point).
842  */
843  pcmk__rsc_info(bundle,
844  "Unable to determine address for bundle %s "
845  "remote connection", bundle->id);
846  }
847  }
848  if (replica->ip != NULL) {
849  replica->ip->priv->cmds->add_actions_to_graph(replica->ip);
850  }
851  replica->container->priv->cmds->add_actions_to_graph(replica->container);
852  if (replica->remote != NULL) {
853  replica->remote->priv->cmds->add_actions_to_graph(replica->remote);
854  }
855  return true;
856 }
857 
864 void
866 {
867  pcmk_resource_t *bundled_resource = NULL;
868 
869  pcmk__assert(pcmk__is_bundle(rsc));
870 
871  bundled_resource = pe__bundled_resource(rsc);
872  if (bundled_resource != NULL) {
873  bundled_resource->priv->cmds->add_actions_to_graph(bundled_resource);
874  }
875  pe__foreach_bundle_replica(rsc, add_replica_actions_to_graph, rsc);
876 }
877 
878 struct probe_data {
879  pcmk_resource_t *bundle; // Bundle being probed
880  pcmk_node_t *node; // Node to create probes on
881  bool any_created; // Whether any probes have been created
882 };
883 
893 static bool
894 order_replica_start_after(pcmk__bundle_replica_t *replica, void *user_data)
895 {
896  pcmk__bundle_replica_t *probed_replica = user_data;
897 
898  if ((replica == probed_replica) || (replica->container == NULL)) {
899  return true;
900  }
901  pcmk__new_ordering(probed_replica->container,
902  pcmk__op_key(probed_replica->container->id,
904  NULL, replica->container,
906  0),
908  replica->container->priv->scheduler);
909  return true;
910 }
911 
921 static bool
922 create_replica_probes(pcmk__bundle_replica_t *replica, void *user_data)
923 {
924  struct probe_data *probe_data = user_data;
925  pcmk_resource_t *bundle = probe_data->bundle;
926 
927  if ((replica->ip != NULL)
928  && replica->ip->priv->cmds->create_probe(replica->ip,
929  probe_data->node)) {
930  probe_data->any_created = true;
931  }
932  if ((replica->child != NULL)
933  && pcmk__same_node(probe_data->node, replica->node)
934  && replica->child->priv->cmds->create_probe(replica->child,
935  probe_data->node)) {
936  probe_data->any_created = true;
937  }
938  if (replica->container->priv->cmds->create_probe(replica->container,
939  probe_data->node)) {
940  probe_data->any_created = true;
941 
942  /* If we're limited to one replica per host (due to
943  * the lack of an IP range probably), then we don't
944  * want any of our peer containers starting until
945  * we've established that no other copies are already
946  * running.
947  *
948  * Partly this is to ensure that the maximum replicas per host is
949  * observed, but also to ensure that the containers
950  * don't fail to start because the necessary port
951  * mappings (which won't include an IP for uniqueness)
952  * are already taken
953  */
954  if (bundle->priv->fns->max_per_node(bundle) == 1) {
955  pe__foreach_bundle_replica(bundle, order_replica_start_after,
956  replica);
957  }
958  }
959  if ((replica->remote != NULL)
960  && replica->remote->priv->cmds->create_probe(replica->remote,
961  probe_data->node)) {
962  /* Do not probe the remote resource until we know where the container is
963  * running. This is required for REMOTE_CONTAINER_HACK to correctly
964  * probe remote resources.
965  */
966  char *probe_uuid = pcmk__op_key(replica->remote->id,
968  pcmk_action_t *probe = NULL;
969 
970  probe = find_first_action(replica->remote->priv->actions, probe_uuid,
971  NULL, probe_data->node);
972  free(probe_uuid);
973  if (probe != NULL) {
974  probe_data->any_created = true;
975  pcmk__rsc_trace(bundle, "Ordering %s probe on %s",
976  replica->remote->id,
977  pcmk__node_name(probe_data->node));
978  pcmk__new_ordering(replica->container,
979  pcmk__op_key(replica->container->id,
980  PCMK_ACTION_START, 0),
981  NULL, replica->remote, NULL, probe,
983  bundle->priv->scheduler);
984  }
985  }
986  return true;
987 }
988 
999 bool
1001 {
1002  struct probe_data probe_data = { rsc, node, false };
1003 
1004  pcmk__assert(pcmk__is_bundle(rsc));
1005  pe__foreach_bundle_replica(rsc, create_replica_probes, &probe_data);
1006  return probe_data.any_created;
1007 }
1008 
1018 static bool
1019 output_replica_actions(pcmk__bundle_replica_t *replica, void *user_data)
1020 {
1021  if (replica->ip != NULL) {
1022  replica->ip->priv->cmds->output_actions(replica->ip);
1023  }
1024  replica->container->priv->cmds->output_actions(replica->container);
1025  if (replica->remote != NULL) {
1026  replica->remote->priv->cmds->output_actions(replica->remote);
1027  }
1028  if (replica->child != NULL) {
1029  replica->child->priv->cmds->output_actions(replica->child);
1030  }
1031  return true;
1032 }
1033 
1040 void
1042 {
1043  pcmk__assert(pcmk__is_bundle(rsc));
1044  pe__foreach_bundle_replica(rsc, output_replica_actions, NULL);
1045 }
1046 
1047 // Bundle implementation of pcmk__assignment_methods_t:add_utilization()
1048 void
1050  const pcmk_resource_t *orig_rsc, GList *all_rscs,
1051  GHashTable *utilization)
1052 {
1053  pcmk_resource_t *container = NULL;
1054 
1055  pcmk__assert(pcmk__is_bundle(rsc));
1056 
1057  if (!pcmk_is_set(rsc->flags, pcmk__rsc_unassigned)) {
1058  return;
1059  }
1060 
1061  /* All bundle replicas are identical, so using the utilization of the first
1062  * is sufficient for any. Only the implicit container resource can have
1063  * utilization values.
1064  */
1065  container = pe__first_container(rsc);
1066  if (container != NULL) {
1067  container->priv->cmds->add_utilization(container, orig_rsc, all_rscs,
1068  utilization);
1069  }
1070 }
1071 
1072 // Bundle implementation of pcmk__assignment_methods_t:shutdown_lock()
1073 void
1075 {
1076  pcmk__assert(pcmk__is_bundle(rsc));
1077  // Bundles currently don't support shutdown locks
1078 }
int pcmk__bundle_apply_coloc_score(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition: complex.c:1043
Relation applies only if actions are on same node.
#define pcmk__order_starts(rsc1, rsc2, flags)
G_GNUC_INTERNAL uint32_t pcmk__collective_action_flags(pcmk_action_t *action, const GList *instances, const pcmk_node_t *node)
#define crm_notice(fmt, args...)
Definition: logging.h:365
&#39;then&#39; is runnable (and migratable) only if &#39;first&#39; is runnable
G_GNUC_INTERNAL void pcmk__apply_location(pcmk_resource_t *rsc, pcmk__location_t *constraint)
void(* create_actions)(pcmk_resource_t *rsc)
void pcmk__bundle_add_utilization(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
pcmk_node_t * node
Copy of node created for this instance.
G_GNUC_INTERNAL void pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_task, pcmk_action_t *first_action, pcmk_resource_t *then_rsc, char *then_task, pcmk_action_t *then_action, uint32_t flags, pcmk_scheduler_t *sched)
pcmk_resource_t * parent
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:102
pcmk_node_t *(* assign)(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
G_GNUC_INTERNAL bool pcmk__threshold_reached(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_resource_t **failed)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__order_stops(rsc1, rsc2, flags)
void pe__foreach_bundle_replica(pcmk_resource_t *bundle, bool(*fn)(pcmk__bundle_replica_t *, void *), void *user_data)
Definition: bundle.c:207
#define pcmk__rsc_info(rsc, fmt, args...)
const char * pe__add_bundle_remote_name(pcmk_resource_t *rsc, xmlNode *xml, const char *field)
Definition: bundle.c:908
#define pcmk__set_rsc_flags(resource, flags_to_set)
pcmk_resource_t * ip
IP address resource for ipaddr.
#define PCMK_ACTION_MONITOR
Definition: actions.h:51
#define PCMK_REMOTE_RA_ADDR
Definition: options.h:122
G_GNUC_INTERNAL void pcmk__create_instance_actions(pcmk_resource_t *rsc, GList *instances)
void pcmk__bundle_add_actions_to_graph(pcmk_resource_t *rsc)
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, uint32_t target)
void(* add_utilization)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
Promoted.
Definition: roles.h:39
uint64_t flags
Definition: scheduler.h:89
void pe__foreach_const_bundle_replica(const pcmk_resource_t *bundle, bool(*fn)(const pcmk__bundle_replica_t *, void *), void *user_data)
Definition: bundle.c:231
const pcmk__rsc_methods_t * fns
void(* add_actions_to_graph)(pcmk_resource_t *rsc)
enum pcmk__action_type get_complex_task(const pcmk_resource_t *rsc, const char *name)
Definition: pe_actions.c:1383
Ordering applies even if &#39;first&#39; runs on guest node created by &#39;then&#39;.
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
void(* internal_constraints)(pcmk_resource_t *rsc)
void(* output_actions)(pcmk_resource_t *rsc)
const char * action
Definition: pcmk_fence.c:32
G_GNUC_INTERNAL bool pcmk__assign_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool force, bool stop_if_fail)
#define pcmk__rsc_debug(rsc, fmt, args...)
pcmk__node_private_t * priv
Definition: nodes.h:85
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1750
#define PCMK_ACTION_DEMOTE
Definition: actions.h:40
G_GNUC_INTERNAL void pcmk__add_with_this_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
int pe__bundle_max(const pcmk_resource_t *rsc)
Definition: bundle.c:93
pcmk_scheduler_t * scheduler
void pcmk__bundle_with_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
Actions are ordered (optionally, if no other flags are set)
enum pcmk__rsc_variant variant
G_GNUC_INTERNAL void pcmk__new_colocation(const char *id, const char *node_attr, int score, pcmk_resource_t *dependent, pcmk_resource_t *primary, const char *dependent_role_spec, const char *primary_role_spec, uint32_t flags)
void pcmk__bundle_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
void(* apply_location)(pcmk_resource_t *rsc, pcmk__location_t *location)
bool pe__bundle_needs_remote_name(pcmk_resource_t *rsc)
Definition: bundle.c:890
#define PCMK_ACTION_START
Definition: actions.h:63
pcmk__resource_private_t * priv
Definition: resources.h:61
bool pcmk__bundle_create_probe(pcmk_resource_t *rsc, pcmk_node_t *node)
G_GNUC_INTERNAL gint pcmk__cmp_instance(gconstpointer a, gconstpointer b)
Unpromoted.
Definition: roles.h:38
Wrappers for and extensions to libxml2.
void pcmk__output_bundle_actions(pcmk_resource_t *rsc)
uint32_t pcmk__bundle_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
#define PCMK_ACTION_STOP
Definition: actions.h:66
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
bool(* create_probe)(pcmk_resource_t *rsc, pcmk_node_t *node)
#define PCMK_XA_VALUE
Definition: xml_names.h:442
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition: clone.c:1084
G_GNUC_INTERNAL void pcmk__assign_instances(pcmk_resource_t *collective, GList *instances, int max_total, int max_per_node)
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: actions.c:195
int pcmk__add_scores(int score1, int score2)
Definition: scores.c:159
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
Definition: clone.c:497
pcmk_resource_t * child
Instance of bundled resource.
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
A single instance of a bundle.
#define pcmk__assert(expr)
void pcmk__with_bundle_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
pcmk_resource_t * container
Container associated with this instance.
If &#39;then&#39; is required, &#39;first&#39; must be added to the transition graph.
G_GNUC_INTERNAL bool pcmk__instance_matches(const pcmk_resource_t *instance, const pcmk_node_t *node, enum rsc_role_e role, bool current)
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
Definition: pe_actions.c:1416
G_GNUC_INTERNAL void pcmk__add_this_with_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
pcmk_resource_t * remote
If &#39;first&#39; is required and runnable, &#39;then&#39; must be in graph.
#define PCMK_ACTION_STOPPED
Definition: actions.h:67
pcmk_resource_t * launcher
pcmk_resource_t * pe__first_container(const pcmk_resource_t *bundle)
Definition: bundle.c:184
enum rsc_role_e role_filter
G_GNUC_INTERNAL void pcmk__promotable_restart_ordering(pcmk_resource_t *rsc)
#define PCMK_ACTION_PROMOTE
Definition: actions.h:57
pcmk_resource_t * dependent
#define pe__show_node_scores(level, rsc, text, nodes, scheduler)
Definition: internal.h:164
unsigned long long flags
Definition: resources.h:69
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pcmk_node_t *active_node)
#define PCMK_ACTION_PROMOTED
Definition: actions.h:58
void pcmk__bundle_create_actions(pcmk_resource_t *rsc)
pcmk_resource_t * pe__bundled_resource(const pcmk_resource_t *rsc)
Definition: bundle.c:110
Resource role is unknown.
Definition: roles.h:35
void pcmk__bundle_shutdown_lock(pcmk_resource_t *rsc)
Location constraint object.
GHashTable * pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get a table of resource parameters.
Definition: complex.c:476
#define PCMK_ACTION_RUNNING
Definition: actions.h:62
unsigned int(* max_per_node)(const pcmk_resource_t *rsc)
bool pe__node_is_bundle_instance(const pcmk_resource_t *bundle, const pcmk_node_t *node)
Definition: bundle.c:158
#define PCMK_ACTION_DEMOTED
Definition: actions.h:41
#define XPATH_REMOTE
pcmk_node_t * pcmk__bundle_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
int(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
pcmk_resource_t * remote
Pacemaker Remote connection into container.
GList * pe__bundle_containers(const pcmk_resource_t *bundle)
Definition: bundle.c:1985
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:703
G_GNUC_INTERNAL void pcmk__colocation_intersect_nodes(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, const GList *primary_nodes, bool merge_scores)
uint64_t flags
Definition: remote.c:211
const pcmk__assignment_methods_t * cmds
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition: scores.h:26
void pcmk__bundle_internal_constraints(pcmk_resource_t *rsc)
struct pcmk__node_assignment * assign
Definition: nodes.h:79