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

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