pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
pcmk_sched_bundle.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2023 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 struct assign_data {
20  const pcmk_node_t *prefer;
21  bool stop_if_fail;
22 };
23 
33 static bool
34 assign_replica(pe__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  pe_rsc_trace(bundle, "Assigning bundle %s IP %s",
47  bundle->id, replica->ip->id);
48  replica->ip->cmds->assign(replica->ip, prefer, stop_if_fail);
49  }
50 
51  container_host = replica->container->allocated_to;
52  if (replica->remote != NULL) {
53  if (pe__is_guest_or_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  INFINITY, replica->remote,
60  container_host->details->remote_rsc, NULL,
61  NULL, pcmk__coloc_influence);
62  }
63  pe_rsc_trace(bundle, "Assigning bundle %s connection %s",
64  bundle->id, replica->remote->id);
65  replica->remote->cmds->assign(replica->remote, prefer, stop_if_fail);
66  }
67 
68  if (replica->child != NULL) {
69  pcmk_node_t *node = NULL;
70  GHashTableIter iter;
71 
72  g_hash_table_iter_init(&iter, replica->child->allowed_nodes);
73  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
74  if (!pe__same_node(node, replica->node)) {
75  node->weight = -INFINITY;
76  } else if (!pcmk__threshold_reached(replica->child, node, NULL)) {
77  node->weight = INFINITY;
78  }
79  }
80 
82  pe_rsc_trace(bundle, "Assigning bundle %s replica child %s",
83  bundle->id, replica->child->id);
84  replica->child->cmds->assign(replica->child, replica->node,
85  stop_if_fail);
87  }
88  return true;
89 }
90 
110 pcmk_node_t *
112  bool stop_if_fail)
113 {
114  GList *containers = NULL;
115  pcmk_resource_t *bundled_resource = NULL;
116  struct assign_data assign_data = { prefer, stop_if_fail };
117 
118  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
119 
120  pe_rsc_trace(rsc, "Assigning bundle %s", rsc->id);
122 
125  rsc, __func__, rsc->allowed_nodes, rsc->cluster);
126 
127  // Assign all containers first, so we know what nodes the bundle will be on
128  containers = g_list_sort(pe__bundle_containers(rsc), pcmk__cmp_instance);
129  pcmk__assign_instances(rsc, containers, pe__bundle_max(rsc),
130  rsc->fns->max_per_node(rsc));
131  g_list_free(containers);
132 
133  // Then assign remaining replica resources
134  pe__foreach_bundle_replica(rsc, assign_replica, (void *) &assign_data);
135 
136  // Finally, assign the bundled resources to each bundle node
137  bundled_resource = pe__bundled_resource(rsc);
138  if (bundled_resource != NULL) {
139  pcmk_node_t *node = NULL;
140  GHashTableIter iter;
141 
142  g_hash_table_iter_init(&iter, bundled_resource->allowed_nodes);
143  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
144  if (pe__node_is_bundle_instance(rsc, node)) {
145  node->weight = 0;
146  } else {
147  node->weight = -INFINITY;
148  }
149  }
150  bundled_resource->cmds->assign(bundled_resource, prefer, stop_if_fail);
151  }
152 
154  return NULL;
155 }
156 
166 static bool
167 create_replica_actions(pe__bundle_replica_t *replica, void *user_data)
168 {
169  if (replica->ip != NULL) {
170  replica->ip->cmds->create_actions(replica->ip);
171  }
172  if (replica->container != NULL) {
173  replica->container->cmds->create_actions(replica->container);
174  }
175  if (replica->remote != NULL) {
176  replica->remote->cmds->create_actions(replica->remote);
177  }
178  return true;
179 }
180 
187 void
189 {
190  pcmk_action_t *action = NULL;
191  GList *containers = NULL;
192  pcmk_resource_t *bundled_resource = NULL;
193 
194  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
195 
196  pe__foreach_bundle_replica(rsc, create_replica_actions, NULL);
197 
198  containers = pe__bundle_containers(rsc);
199  pcmk__create_instance_actions(rsc, containers);
200  g_list_free(containers);
201 
202  bundled_resource = pe__bundled_resource(rsc);
203  if (bundled_resource != NULL) {
204  bundled_resource->cmds->create_actions(bundled_resource);
205 
206  if (pcmk_is_set(bundled_resource->flags, pcmk_rsc_promotable)) {
209  true, true);
210  action->priority = INFINITY;
211 
214  true, true);
215  action->priority = INFINITY;
216  }
217  }
218 }
219 
229 static bool
230 replica_internal_constraints(pe__bundle_replica_t *replica, void *user_data)
231 {
232  pcmk_resource_t *bundle = user_data;
233 
234  replica->container->cmds->internal_constraints(replica->container);
235 
236  // Start bundle -> start replica container
237  pcmk__order_starts(bundle, replica->container,
240 
241  // Stop bundle -> stop replica child and container
242  if (replica->child != NULL) {
243  pcmk__order_stops(bundle, replica->child,
245  }
246  pcmk__order_stops(bundle, replica->container,
248 
249  // Start replica container -> bundle is started
253 
254  // Stop replica container -> bundle is stopped
258 
259  if (replica->ip != NULL) {
260  replica->ip->cmds->internal_constraints(replica->ip);
261 
262  // Replica IP address -> replica container (symmetric)
263  pcmk__order_starts(replica->ip, replica->container,
266  pcmk__order_stops(replica->container, replica->ip,
268 
269  pcmk__new_colocation("#ip-with-container", NULL, INFINITY, replica->ip,
270  replica->container, NULL, NULL,
272  }
273 
274  if (replica->remote != NULL) {
275  /* This handles ordering and colocating remote relative to container
276  * (via "#resource-with-container"). Since IP is also ordered and
277  * colocated relative to the container, we don't need to do anything
278  * explicit here with IP.
279  */
280  replica->remote->cmds->internal_constraints(replica->remote);
281  }
282 
283  if (replica->child != NULL) {
284  CRM_ASSERT(replica->remote != NULL);
285  // "Start remote then child" is implicit in scheduler's remote logic
286  }
287  return true;
288 }
289 
296 void
298 {
299  pcmk_resource_t *bundled_resource = NULL;
300 
301  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
302 
303  pe__foreach_bundle_replica(rsc, replica_internal_constraints, rsc);
304 
305  bundled_resource = pe__bundled_resource(rsc);
306  if (bundled_resource == NULL) {
307  return;
308  }
309 
310  // Start bundle -> start bundled clone
311  pcmk__order_resource_actions(rsc, PCMK_ACTION_START, bundled_resource,
314 
315  // Bundled clone is started -> bundle is started
317  rsc, PCMK_ACTION_RUNNING,
319 
320  // Stop bundle -> stop bundled clone
321  pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP, bundled_resource,
324 
325  // Bundled clone is stopped -> bundle is stopped
327  rsc, PCMK_ACTION_STOPPED,
329 
330  bundled_resource->cmds->internal_constraints(bundled_resource);
331 
332  if (!pcmk_is_set(bundled_resource->flags, pcmk_rsc_promotable)) {
333  return;
334  }
336 
337  // Demote bundle -> demote bundled clone
338  pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTE, bundled_resource,
341 
342  // Bundled clone is demoted -> bundle is demoted
344  rsc, PCMK_ACTION_DEMOTED,
346 
347  // Promote bundle -> promote bundled clone
349  bundled_resource, PCMK_ACTION_PROMOTE,
351 
352  // Bundled clone is promoted -> bundle is promoted
356 }
357 
358 struct match_data {
359  const pcmk_node_t *node; // Node to compare against replica
360  pcmk_resource_t *container; // Replica container corresponding to node
361 };
362 
373 static bool
374 match_replica_container(const pe__bundle_replica_t *replica, void *user_data)
375 {
376  struct match_data *match_data = user_data;
377 
378  if (pcmk__instance_matches(replica->container, match_data->node,
379  pcmk_role_unknown, false)) {
380  match_data->container = replica->container;
381  return false; // Match found, don't bother searching further replicas
382  }
383  return true; // No match, keep searching
384 }
385 
395 static const pcmk_node_t *
396 get_bundle_node_host(const pcmk_node_t *node)
397 {
398  if (pe__is_bundle_node(node)) {
399  const pcmk_resource_t *container = node->details->remote_rsc->container;
400 
401  return container->fns->location(container, NULL, 0);
402  }
403  return node;
404 }
405 
417 static pcmk_resource_t *
418 compatible_container(const pcmk_resource_t *dependent,
419  const pcmk_resource_t *bundle)
420 {
421  GList *scratch = NULL;
422  struct match_data match_data = { NULL, NULL };
423 
424  // If dependent is assigned, only check there
425  match_data.node = dependent->fns->location(dependent, NULL, 0);
426  match_data.node = get_bundle_node_host(match_data.node);
427  if (match_data.node != NULL) {
428  pe__foreach_const_bundle_replica(bundle, match_replica_container,
429  &match_data);
430  return match_data.container;
431  }
432 
433  // Otherwise, check for any of the dependent's allowed nodes
434  scratch = g_hash_table_get_values(dependent->allowed_nodes);
435  scratch = pcmk__sort_nodes(scratch, NULL);
436  for (const GList *iter = scratch; iter != NULL; iter = iter->next) {
437  match_data.node = iter->data;
438  match_data.node = get_bundle_node_host(match_data.node);
439  if (match_data.node == NULL) {
440  continue;
441  }
442 
443  pe__foreach_const_bundle_replica(bundle, match_replica_container,
444  &match_data);
445  if (match_data.container != NULL) {
446  break;
447  }
448  }
449  g_list_free(scratch);
450  return match_data.container;
451 }
452 
453 struct coloc_data {
454  const pcmk__colocation_t *colocation;
455  pcmk_resource_t *dependent;
456  GList *container_hosts;
457 };
458 
468 static bool
469 replica_apply_coloc_score(const pe__bundle_replica_t *replica, void *user_data)
470 {
471  struct coloc_data *coloc_data = user_data;
472  pcmk_node_t *chosen = NULL;
473 
474  if (coloc_data->colocation->score < INFINITY) {
475  replica->container->cmds->apply_coloc_score(coloc_data->dependent,
476  replica->container,
477  coloc_data->colocation,
478  false);
479  return true;
480  }
481 
482  chosen = replica->container->fns->location(replica->container, NULL, 0);
483  if ((chosen == NULL)
484  || is_set_recursive(replica->container, pcmk_rsc_blocked, true)) {
485  return true;
486  }
487 
488  if ((coloc_data->colocation->primary_role >= pcmk_role_promoted)
489  && ((replica->child == NULL)
490  || (replica->child->next_role < pcmk_role_promoted))) {
491  return true;
492  }
493 
495  "Allowing mandatory colocation %s using %s @%d",
496  coloc_data->colocation->id, pe__node_name(chosen),
497  chosen->weight);
498  coloc_data->container_hosts = g_list_prepend(coloc_data->container_hosts,
499  chosen);
500  return true;
501 }
502 
516 void
518  const pcmk_resource_t *primary,
519  const pcmk__colocation_t *colocation,
520  bool for_dependent)
521 {
522  struct coloc_data coloc_data = { colocation, dependent, NULL };
523 
524  /* This should never be called for the bundle itself as a dependent.
525  * Instead, we add its colocation constraints to its containers and bundled
526  * primitive and call the apply_coloc_score() method for them as dependents.
527  */
528  CRM_ASSERT((primary != NULL)
529  && (primary->variant == pcmk_rsc_variant_bundle)
530  && (dependent != NULL)
531  && (dependent->variant == pcmk_rsc_variant_primitive)
532  && (colocation != NULL) && !for_dependent);
533 
534  if (pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
535  pe_rsc_trace(primary,
536  "Skipping applying colocation %s "
537  "because %s is still provisional",
538  colocation->id, primary->id);
539  return;
540  }
541  pe_rsc_trace(primary, "Applying colocation %s (%s with %s at %s)",
542  colocation->id, dependent->id, primary->id,
543  pcmk_readable_score(colocation->score));
544 
545  /* If the constraint dependent is a clone or bundle, "dependent" here is one
546  * of its instances. Look for a compatible instance of this bundle.
547  */
548  if (colocation->dependent->variant > pcmk_rsc_variant_group) {
549  const pcmk_resource_t *primary_container = NULL;
550 
551  primary_container = compatible_container(dependent, primary);
552  if (primary_container != NULL) { // Success, we found one
553  pe_rsc_debug(primary, "Pairing %s with %s",
554  dependent->id, primary_container->id);
555  dependent->cmds->apply_coloc_score(dependent, primary_container,
556  colocation, true);
557 
558  } else if (colocation->score >= INFINITY) { // Failure, and it's fatal
559  crm_notice("%s cannot run because there is no compatible "
560  "instance of %s to colocate with",
561  dependent->id, primary->id);
562  pcmk__assign_resource(dependent, NULL, true, true);
563 
564  } else { // Failure, but we can ignore it
565  pe_rsc_debug(primary,
566  "%s cannot be colocated with any instance of %s",
567  dependent->id, primary->id);
568  }
569  return;
570  }
571 
572  pe__foreach_const_bundle_replica(primary, replica_apply_coloc_score,
573  &coloc_data);
574 
575  if (colocation->score >= INFINITY) {
576  pcmk__colocation_intersect_nodes(dependent, primary, colocation,
577  coloc_data.container_hosts, false);
578  }
579  g_list_free(coloc_data.container_hosts);
580 }
581 
582 // Bundle implementation of pcmk_assignment_methods_t:with_this_colocations()
583 void
585  const pcmk_resource_t *orig_rsc, GList **list)
586 {
587  const pcmk_resource_t *bundled_rsc = NULL;
588 
589  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle)
590  && (orig_rsc != NULL) && (list != NULL));
591 
592  // The bundle itself and its containers always get its colocations
593  if ((orig_rsc == rsc)
595 
596  pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
597  return;
598  }
599 
600  /* The bundled resource gets the colocations if it's promotable and we've
601  * begun choosing roles
602  */
603  bundled_rsc = pe__bundled_resource(rsc);
604  if ((bundled_rsc == NULL)
605  || !pcmk_is_set(bundled_rsc->flags, pcmk_rsc_promotable)
606  || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
607  return;
608  }
609 
610  if (orig_rsc == bundled_rsc) {
611  if (pe__clone_flag_is_set(orig_rsc,
613  /* orig_rsc is the clone and we're setting roles (or have already
614  * done so)
615  */
616  pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
617  }
618 
619  } else if (!pcmk_is_set(orig_rsc->flags, pcmk_rsc_unassigned)) {
620  /* orig_rsc is an instance and is already assigned. If something
621  * requests colocations for orig_rsc now, it's for setting roles.
622  */
623  pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
624  }
625 }
626 
627 // Bundle implementation of pcmk_assignment_methods_t:this_with_colocations()
628 void
630  const pcmk_resource_t *orig_rsc, GList **list)
631 {
632  const pcmk_resource_t *bundled_rsc = NULL;
633 
634  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle)
635  && (orig_rsc != NULL) && (list != NULL));
636 
637  // The bundle itself and its containers always get its colocations
638  if ((orig_rsc == rsc)
640 
641  pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
642  return;
643  }
644 
645  /* The bundled resource gets the colocations if it's promotable and we've
646  * begun choosing roles
647  */
648  bundled_rsc = pe__bundled_resource(rsc);
649  if ((bundled_rsc == NULL)
650  || !pcmk_is_set(bundled_rsc->flags, pcmk_rsc_promotable)
651  || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
652  return;
653  }
654 
655  if (orig_rsc == bundled_rsc) {
656  if (pe__clone_flag_is_set(orig_rsc,
658  /* orig_rsc is the clone and we're setting roles (or have already
659  * done so)
660  */
661  pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
662  }
663 
664  } else if (!pcmk_is_set(orig_rsc->flags, pcmk_rsc_unassigned)) {
665  /* orig_rsc is an instance and is already assigned. If something
666  * requests colocations for orig_rsc now, it's for setting roles.
667  */
668  pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
669  }
670 }
671 
681 uint32_t
683 {
684  GList *containers = NULL;
685  uint32_t flags = 0;
686  pcmk_resource_t *bundled_resource = NULL;
687 
688  CRM_ASSERT((action != NULL) && (action->rsc != NULL)
689  && (action->rsc->variant == pcmk_rsc_variant_bundle));
690 
691  bundled_resource = pe__bundled_resource(action->rsc);
692  if (bundled_resource != NULL) {
693  // Clone actions are done on the bundled clone resource, not container
694  switch (get_complex_task(bundled_resource, action->task)) {
696  case pcmk_action_notify:
698  case pcmk_action_promote:
700  case pcmk_action_demote:
701  case pcmk_action_demoted:
703  bundled_resource->children,
704  node);
705  default:
706  break;
707  }
708  }
709 
710  containers = pe__bundle_containers(action->rsc);
711  flags = pcmk__collective_action_flags(action, containers, node);
712  g_list_free(containers);
713  return flags;
714 }
715 
725 static bool
726 apply_location_to_replica(pe__bundle_replica_t *replica, void *user_data)
727 {
728  pe__location_t *location = user_data;
729 
730  if (replica->container != NULL) {
731  replica->container->cmds->apply_location(replica->container, location);
732  }
733  if (replica->ip != NULL) {
734  replica->ip->cmds->apply_location(replica->ip, location);
735  }
736  return true;
737 }
738 
746 void
748 {
749  pcmk_resource_t *bundled_resource = NULL;
750 
751  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle)
752  && (location != NULL));
753 
754  pcmk__apply_location(rsc, location);
755  pe__foreach_bundle_replica(rsc, apply_location_to_replica, location);
756 
757  bundled_resource = pe__bundled_resource(rsc);
758  if ((bundled_resource != NULL)
759  && ((location->role_filter == pcmk_role_unpromoted)
760  || (location->role_filter == pcmk_role_promoted))) {
761  bundled_resource->cmds->apply_location(bundled_resource, location);
762  bundled_resource->rsc_location = g_list_prepend(
763  bundled_resource->rsc_location, location);
764  }
765 }
766 
767 #define XPATH_REMOTE "//nvpair[@name='" XML_RSC_ATTR_REMOTE_RA_ADDR "']"
768 
778 static bool
779 add_replica_actions_to_graph(pe__bundle_replica_t *replica, void *user_data)
780 {
781  if ((replica->remote != NULL) && (replica->container != NULL)
782  && pe__bundle_needs_remote_name(replica->remote)) {
783 
784  /* REMOTE_CONTAINER_HACK: Allow remote nodes to run containers that
785  * run pacemaker-remoted inside, without needing a separate IP for
786  * the container. This is done by configuring the inner remote's
787  * connection host as the magic string "#uname", then
788  * replacing it with the underlying host when needed.
789  */
790  xmlNode *nvpair = get_xpath_object(XPATH_REMOTE, replica->remote->xml,
791  LOG_ERR);
792  const char *calculated_addr = NULL;
793 
794  // Replace the value in replica->remote->xml (if appropriate)
795  calculated_addr = pe__add_bundle_remote_name(replica->remote,
796  replica->remote->cluster,
797  nvpair, "value");
798  if (calculated_addr != NULL) {
799  /* Since this is for the bundle as a resource, and not any
800  * particular action, replace the value in the default
801  * parameters (not evaluated for node). create_graph_action()
802  * will grab it from there to replace it in node-evaluated
803  * parameters.
804  */
805  GHashTable *params = pe_rsc_params(replica->remote,
806  NULL, replica->remote->cluster);
807 
808  g_hash_table_replace(params,
810  strdup(calculated_addr));
811  } else {
812  pcmk_resource_t *bundle = user_data;
813 
814  /* The only way to get here is if the remote connection is
815  * neither currently running nor scheduled to run. That means we
816  * won't be doing any operations that require addr (only start
817  * requires it; we additionally use it to compare digests when
818  * unpacking status, promote, and migrate_from history, but
819  * that's already happened by this point).
820  */
821  pe_rsc_info(bundle,
822  "Unable to determine address for bundle %s "
823  "remote connection", bundle->id);
824  }
825  }
826  if (replica->ip != NULL) {
827  replica->ip->cmds->add_actions_to_graph(replica->ip);
828  }
829  if (replica->container != NULL) {
830  replica->container->cmds->add_actions_to_graph(replica->container);
831  }
832  if (replica->remote != NULL) {
833  replica->remote->cmds->add_actions_to_graph(replica->remote);
834  }
835  return true;
836 }
837 
844 void
846 {
847  pcmk_resource_t *bundled_resource = NULL;
848 
849  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
850 
851  bundled_resource = pe__bundled_resource(rsc);
852  if (bundled_resource != NULL) {
853  bundled_resource->cmds->add_actions_to_graph(bundled_resource);
854  }
855  pe__foreach_bundle_replica(rsc, add_replica_actions_to_graph, rsc);
856 }
857 
858 struct probe_data {
859  pcmk_resource_t *bundle; // Bundle being probed
860  pcmk_node_t *node; // Node to create probes on
861  bool any_created; // Whether any probes have been created
862 };
863 
873 static bool
874 order_replica_start_after(pe__bundle_replica_t *replica, void *user_data)
875 {
876  pe__bundle_replica_t *probed_replica = user_data;
877 
878  if ((replica == probed_replica) || (replica->container == NULL)) {
879  return true;
880  }
881  pcmk__new_ordering(probed_replica->container,
882  pcmk__op_key(probed_replica->container->id,
884  NULL, replica->container,
886  0),
888  replica->container->cluster);
889  return true;
890 }
891 
901 static bool
902 create_replica_probes(pe__bundle_replica_t *replica, void *user_data)
903 {
904  struct probe_data *probe_data = user_data;
905 
906  if ((replica->ip != NULL)
907  && replica->ip->cmds->create_probe(replica->ip, probe_data->node)) {
908  probe_data->any_created = true;
909  }
910  if ((replica->child != NULL)
911  && pe__same_node(probe_data->node, replica->node)
912  && replica->child->cmds->create_probe(replica->child,
913  probe_data->node)) {
914  probe_data->any_created = true;
915  }
916  if ((replica->container != NULL)
917  && replica->container->cmds->create_probe(replica->container,
918  probe_data->node)) {
919  probe_data->any_created = true;
920 
921  /* If we're limited to one replica per host (due to
922  * the lack of an IP range probably), then we don't
923  * want any of our peer containers starting until
924  * we've established that no other copies are already
925  * running.
926  *
927  * Partly this is to ensure that the maximum replicas per host is
928  * observed, but also to ensure that the containers
929  * don't fail to start because the necessary port
930  * mappings (which won't include an IP for uniqueness)
931  * are already taken
932  */
933  if (probe_data->bundle->fns->max_per_node(probe_data->bundle) == 1) {
934  pe__foreach_bundle_replica(probe_data->bundle,
935  order_replica_start_after, replica);
936  }
937  }
938  if ((replica->container != NULL) && (replica->remote != NULL)
939  && replica->remote->cmds->create_probe(replica->remote,
940  probe_data->node)) {
941  /* Do not probe the remote resource until we know where the container is
942  * running. This is required for REMOTE_CONTAINER_HACK to correctly
943  * probe remote resources.
944  */
945  char *probe_uuid = pcmk__op_key(replica->remote->id,
947  pcmk_action_t *probe = find_first_action(replica->remote->actions,
948  probe_uuid, NULL,
949  probe_data->node);
950 
951  free(probe_uuid);
952  if (probe != NULL) {
953  probe_data->any_created = true;
954  pe_rsc_trace(probe_data->bundle, "Ordering %s probe on %s",
955  replica->remote->id, pe__node_name(probe_data->node));
956  pcmk__new_ordering(replica->container,
957  pcmk__op_key(replica->container->id,
958  PCMK_ACTION_START, 0),
959  NULL, replica->remote, NULL, probe,
961  probe_data->bundle->cluster);
962  }
963  }
964  return true;
965 }
966 
977 bool
979 {
980  struct probe_data probe_data = { rsc, node, false };
981 
982  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
983  pe__foreach_bundle_replica(rsc, create_replica_probes, &probe_data);
984  return probe_data.any_created;
985 }
986 
996 static bool
997 output_replica_actions(pe__bundle_replica_t *replica, void *user_data)
998 {
999  if (replica->ip != NULL) {
1000  replica->ip->cmds->output_actions(replica->ip);
1001  }
1002  if (replica->container != NULL) {
1003  replica->container->cmds->output_actions(replica->container);
1004  }
1005  if (replica->remote != NULL) {
1006  replica->remote->cmds->output_actions(replica->remote);
1007  }
1008  if (replica->child != NULL) {
1009  replica->child->cmds->output_actions(replica->child);
1010  }
1011  return true;
1012 }
1013 
1020 void
1022 {
1023  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
1024  pe__foreach_bundle_replica(rsc, output_replica_actions, NULL);
1025 }
1026 
1027 // Bundle implementation of pcmk_assignment_methods_t:add_utilization()
1028 void
1030  const pcmk_resource_t *orig_rsc, GList *all_rscs,
1031  GHashTable *utilization)
1032 {
1033  pcmk_resource_t *container = NULL;
1034 
1035  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
1036 
1037  if (!pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
1038  return;
1039  }
1040 
1041  /* All bundle replicas are identical, so using the utilization of the first
1042  * is sufficient for any. Only the implicit container resource can have
1043  * utilization values.
1044  */
1045  container = pe__first_container(rsc);
1046  if (container != NULL) {
1047  container->cmds->add_utilization(container, orig_rsc, all_rscs,
1048  utilization);
1049  }
1050 }
1051 
1052 // Bundle implementation of pcmk_assignment_methods_t:shutdown_lock()
1053 void
1055 {
1056  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_bundle));
1057  // Bundles currently don't support shutdown locks
1058 }
pcmk_assignment_methods_t * cmds
Resource assignment methods.
Definition: resources.h:417
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition: complex.c:962
Demoted.
Definition: actions.h:98
enum rsc_role_e role_filter
Definition: internal.h:161
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)
void pcmk__bundle_apply_location(pcmk_resource_t *rsc, pe__location_t *location)
#define crm_notice(fmt, args...)
Definition: logging.h:383
&#39;then&#39; is runnable (and migratable) only if &#39;first&#39; is runnable
bool pe__is_guest_or_remote_node(const pcmk_node_t *node)
Definition: remote.c:41
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition: resources.h:412
void(* output_actions)(pcmk_resource_t *rsc)
pcmk_resource_t * ip
IP address resource for ipaddr.
Definition: internal.h:523
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:36
#define INFINITY
Definition: crm.h:98
GList * rsc_cons
Definition: resources.h:445
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
List nodes where a resource (or any of its children) is.
Definition: resources.h:339
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)
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)
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:86
Whether resource is an implicit container resource for a bundle replica.
Definition: resources.h:178
Notify.
Definition: actions.h:91
G_GNUC_INTERNAL bool pcmk__threshold_reached(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_resource_t **failed)
GList * children
Resource&#39;s child resources, if any.
Definition: resources.h:475
#define pcmk__order_stops(rsc1, rsc2, flags)
xmlNode * xml
Resource configuration (possibly expanded from template)
Definition: resources.h:404
enum rsc_role_e next_role
Resource&#39;s scheduled next role.
Definition: resources.h:469
Implementation of pcmk_action_t.
Definition: actions.h:390
Whether node scores should be output instead of logged.
Definition: scheduler.h:158
#define PCMK_ACTION_MONITOR
Definition: actions.h:59
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)
Promoted.
Definition: roles.h:32
pcmk_node_t *(* assign)(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
Group resource.
Definition: resources.h:35
GList * rsc_cons_lhs
Definition: resources.h:444
void pe__foreach_const_bundle_replica(const pcmk_resource_t *bundle, bool(*fn)(const pe__bundle_replica_t *, void *), void *user_data)
Definition: bundle.c:234
pcmk_resource_t * container
Resource containing this one, if any.
Definition: resources.h:480
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:211
pcmk_resource_t * remote
Pacemaker Remote connection into container.
Definition: internal.h:526
#define XML_RSC_ATTR_REMOTE_RA_ADDR
Definition: msg_xml.h:261
const char * action
Definition: pcmk_fence.c:30
G_GNUC_INTERNAL bool pcmk__assign_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool force, bool stop_if_fail)
void(* add_actions_to_graph)(pcmk_resource_t *rsc)
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:64
void pcmk__bundle_apply_coloc_score(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
Notify completed.
Definition: actions.h:92
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1835
#define PCMK_ACTION_DEMOTE
Definition: actions.h:49
int weight
Node score for a given resource.
Definition: nodes.h:131
pcmk_resource_t * parent
Resource&#39;s parent resource, if any.
Definition: resources.h:413
Whether resource is in the process of being assigned to a node.
Definition: resources.h:130
Bundle resource.
Definition: resources.h:37
Promote.
Definition: actions.h:94
G_GNUC_INTERNAL void pcmk__add_with_this_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
unsigned int(* max_per_node)(const pcmk_resource_t *rsc)
Get maximum resource instances per node.
Definition: resources.h:395
Implementation of pcmk_resource_t.
Definition: resources.h:399
int pe__bundle_max(const pcmk_resource_t *rsc)
Definition: bundle.c:96
const char * pe__add_bundle_remote_name(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler, xmlNode *xml, const char *field)
Definition: bundle.c:938
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)
pcmk_node_t * node
Node created for this instance.
Definition: internal.h:522
Demote.
Definition: actions.h:97
void(* apply_location)(pcmk_resource_t *rsc, pe__location_t *location)
Primitive resource.
Definition: resources.h:34
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:99
struct pe_node_shared_s * details
Basic node information.
Definition: nodes.h:134
bool pe__bundle_needs_remote_name(pcmk_resource_t *rsc)
Definition: bundle.c:920
#define PCMK_ACTION_START
Definition: actions.h:71
bool pcmk__bundle_create_probe(pcmk_resource_t *rsc, pcmk_node_t *node)
G_GNUC_INTERNAL gint pcmk__cmp_instance(gconstpointer a, gconstpointer b)
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition: resources.h:429
Unpromoted.
Definition: roles.h:31
pcmk_resource_t * container
Container associated with this instance.
Definition: internal.h:525
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:74
GList * actions
Definition: resources.h:447
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition: clone.c:1343
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:42
Whether resource is blocked from further action.
Definition: resources.h:109
Implementation of pcmk_node_t.
Definition: nodes.h:130
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
Definition: clone.c:558
enum pe_obj_types variant
Resource variant.
Definition: resources.h:414
bool(* create_probe)(pcmk_resource_t *rsc, pcmk_node_t *node)
G_GNUC_INTERNAL void pcmk__apply_location(pcmk_resource_t *rsc, pe__location_t *constraint)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
void(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
bool pe__is_bundle_node(const pcmk_node_t *node)
Definition: remote.c:47
void pcmk__with_bundle_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
Unspecified or unknown action.
Definition: actions.h:80
Whether resource has not yet been assigned to a node.
Definition: resources.h:127
If &#39;then&#39; is required, &#39;first&#39; must be added to the transition graph.
void(* internal_constraints)(pcmk_resource_t *rsc)
pcmk_rsc_methods_t * fns
Resource object methods.
Definition: resources.h:416
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:1486
G_GNUC_INTERNAL void pcmk__add_this_with_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
#define CRM_ASSERT(expr)
Definition: results.h:42
If &#39;first&#39; is required and runnable, &#39;then&#39; must be in graph.
#define PCMK_ACTION_STOPPED
Definition: actions.h:75
pcmk_resource_t * pe__first_container(const pcmk_resource_t *bundle)
Definition: bundle.c:187
void pe__foreach_bundle_replica(pcmk_resource_t *bundle, bool(*fn)(pe__bundle_replica_t *, void *), void *user_data)
Definition: bundle.c:210
pcmk_node_t * allocated_to
Node resource is assigned to.
Definition: resources.h:451
GList * rsc_location
Definition: resources.h:446
G_GNUC_INTERNAL void pcmk__promotable_restart_ordering(pcmk_resource_t *rsc)
pcmk_resource_t * child
Instance of bundled resource.
Definition: internal.h:524
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:70
#define PCMK_ACTION_PROMOTE
Definition: actions.h:65
pcmk_resource_t * dependent
#define pe__show_node_scores(level, rsc, text, nodes, scheduler)
Definition: internal.h:341
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pcmk_node_t *active_node)
A single instance of a bundle.
Definition: internal.h:519
#define PCMK_ACTION_PROMOTED
Definition: actions.h:66
void pcmk__bundle_create_actions(pcmk_resource_t *rsc)
pcmk_resource_t * pe__bundled_resource(const pcmk_resource_t *rsc)
Definition: bundle.c:113
Whether resource can be promoted and demoted.
Definition: resources.h:124
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, const char *primary_role, uint32_t flags)
Resource role is unknown.
Definition: roles.h:28
void pcmk__bundle_shutdown_lock(pcmk_resource_t *rsc)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:37
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:446
#define PCMK_ACTION_RUNNING
Definition: actions.h:70
unsigned long long flags
Group of enum pcmk_scheduler_flags.
Definition: scheduler.h:183
bool pe__node_is_bundle_instance(const pcmk_resource_t *bundle, const pcmk_node_t *node)
Definition: bundle.c:161
#define PCMK_ACTION_DEMOTED
Definition: actions.h:50
enum action_tasks get_complex_task(const pcmk_resource_t *rsc, const char *name)
Definition: pe_actions.c:1453
#define XPATH_REMOTE
Promoted.
Definition: actions.h:95
pcmk_node_t * pcmk__bundle_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
void(* add_utilization)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
GList * pe__bundle_containers(const pcmk_resource_t *bundle)
Definition: bundle.c:2113
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:215
pcmk_resource_t * remote_rsc
Remote connection resource for node, if it is a Pacemaker Remote node.
Definition: nodes.h:111
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:35
char * id
Resource ID in configuration.
Definition: resources.h:400
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition: resources.h:466
void pcmk__bundle_internal_constraints(pcmk_resource_t *rsc)