root/lib/pacemaker/pcmk_sched_bundle.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_bundle_node
  2. get_container_list
  3. get_containers_or_children
  4. pcmk__bundle_allocate
  5. pcmk__bundle_create_actions
  6. pcmk__bundle_internal_constraints
  7. compatible_replica_for_node
  8. compatible_replica
  9. copies_per_node
  10. pcmk__bundle_apply_coloc_score
  11. pcmk__bundle_action_flags
  12. find_compatible_child_by_node
  13. replica_for_container
  14. multi_update_interleave_actions
  15. can_interleave_actions
  16. pcmk__multi_update_actions
  17. pcmk__bundle_rsc_location
  18. pcmk__bundle_expand
  19. pcmk__bundle_create_probe
  20. pcmk__output_bundle_actions
  21. pcmk__bundle_add_utilization
  22. pcmk__bundle_shutdown_lock

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

/* [previous][next][first][last][top][bottom][index][help] */