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

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