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. pcmk__bundle_rsc_colocation_lh
  10. copies_per_node
  11. pcmk__bundle_rsc_colocation_rh
  12. pcmk__bundle_action_flags
  13. find_compatible_child_by_node
  14. replica_for_container
  15. multi_update_interleave_actions
  16. can_interleave_actions
  17. pcmk__multi_update_actions
  18. pcmk__bundle_rsc_location
  19. pcmk__bundle_expand
  20. pcmk__bundle_create_probe
  21. pcmk__bundle_append_meta
  22. pcmk__bundle_log_actions

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

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