root/lib/pacemaker/pcmk_sched_clone.c

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

DEFINITIONS

This source file includes following definitions.
  1. sort_rsc_id
  2. parent_node_instance
  3. did_fail
  4. order_instance_by_colocation
  5. sort_clone_instance
  6. can_run_instance
  7. allocate_instance
  8. append_parent_colocation
  9. distribute_children
  10. pcmk__clone_allocate
  11. clone_update_pseudo_status
  12. find_rsc_action
  13. child_ordering_constraints
  14. clone_create_actions
  15. clone_create_pseudo_actions
  16. clone_internal_constraints
  17. assign_node
  18. is_child_compatible
  19. find_compatible_child
  20. clone_rsc_colocation_lh
  21. clone_rsc_colocation_rh
  22. clone_child_action
  23. summary_action_flags
  24. clone_action_flags
  25. clone_rsc_location
  26. clone_expand
  27. rsc_known_on
  28. find_instance_on
  29. probe_unique_clone
  30. probe_anonymous_clone
  31. clone_create_probe
  32. clone_append_meta

   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 <crm/msg_xml.h>
  13 #include <pacemaker-internal.h>
  14 
  15 #define VARIANT_CLONE 1
  16 #include <lib/pengine/variant.h>
  17 
  18 gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
  19 static void append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all);
  20 
  21 static gint
  22 sort_rsc_id(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
  23 {
  24     const pe_resource_t *resource1 = (const pe_resource_t *)a;
  25     const pe_resource_t *resource2 = (const pe_resource_t *)b;
  26     long num1, num2;
  27 
  28     CRM_ASSERT(resource1 != NULL);
  29     CRM_ASSERT(resource2 != NULL);
  30 
  31     /*
  32      * Sort clone instances numerically by instance number, so instance :10
  33      * comes after :9.
  34      */
  35     num1 = strtol(strrchr(resource1->id, ':') + 1, NULL, 10);
  36     num2 = strtol(strrchr(resource2->id, ':') + 1, NULL, 10);
  37     if (num1 < num2) {
  38         return -1;
  39     } else if (num1 > num2) {
  40         return 1;
  41     }
  42     return 0;
  43 }
  44 
  45 static pe_node_t *
  46 parent_node_instance(const pe_resource_t * rsc, pe_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48     pe_node_t *ret = NULL;
  49 
  50     if (node != NULL && rsc->parent) {
  51         ret = pe_hash_table_lookup(rsc->parent->allowed_nodes, node->details->id);
  52     } else if(node != NULL) {
  53         ret = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
  54     }
  55     return ret;
  56 }
  57 
  58 static gboolean
  59 did_fail(const pe_resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61     GList *gIter = rsc->children;
  62 
  63     if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
  64         return TRUE;
  65     }
  66 
  67     for (; gIter != NULL; gIter = gIter->next) {
  68         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
  69 
  70         if (did_fail(child_rsc)) {
  71             return TRUE;
  72         }
  73     }
  74     return FALSE;
  75 }
  76 
  77 /*!
  78  * \internal
  79  * \brief Compare instances based on colocation scores.
  80  *
  81  * Determines the relative order in which \c rsc1 and \c rsc2 should be
  82  * allocated. If one resource compares less than the other, then it
  83  * should be allocated first.
  84  *
  85  * \param[in] rsc1  The first instance to compare.
  86  * \param[in] rsc2  The second instance to compare.
  87  * \param[in] data_set  Cluster working set.
  88  *
  89  * \return -1 if `rsc1 < rsc2`,
  90  *          0 if `rsc1 == rsc2`, or
  91  *          1 if `rsc1 > rsc2`
  92  */
  93 static int
  94 order_instance_by_colocation(const pe_resource_t *rsc1,
     /* [previous][next][first][last][top][bottom][index][help] */
  95                              const pe_resource_t *rsc2,
  96                              pe_working_set_t *data_set)
  97 {
  98     int rc = 0;
  99     pe_node_t *n = NULL;
 100     pe_node_t *node1 = NULL;
 101     pe_node_t *node2 = NULL;
 102     pe_node_t *current_node1 = pe__current_node(rsc1);
 103     pe_node_t *current_node2 = pe__current_node(rsc2);
 104     GList *list1 = NULL;
 105     GList *list2 = NULL;
 106     GHashTable *hash1 = pcmk__strkey_table(NULL, free);
 107     GHashTable *hash2 = pcmk__strkey_table(NULL, free);
 108 
 109     /* Clone instances must have parents */
 110     CRM_ASSERT(rsc1->parent != NULL);
 111     CRM_ASSERT(rsc2->parent != NULL);
 112 
 113     n = pe__copy_node(current_node1);
 114     g_hash_table_insert(hash1, (gpointer) n->details->id, n);
 115 
 116     n = pe__copy_node(current_node2);
 117     g_hash_table_insert(hash2, (gpointer) n->details->id, n);
 118 
 119     /* Apply rsc1's parental colocations */
 120     for (GList *gIter = rsc1->parent->rsc_cons; gIter != NULL;
 121          gIter = gIter->next) {
 122 
 123         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 124 
 125         crm_trace("Applying %s to %s", constraint->id, rsc1->id);
 126 
 127         hash1 = pcmk__native_merge_weights(constraint->rsc_rh, rsc1->id, hash1,
 128                                            constraint->node_attribute,
 129                                            constraint->score / (float) INFINITY,
 130                                            0);
 131     }
 132 
 133     for (GList *gIter = rsc1->parent->rsc_cons_lhs; gIter != NULL;
 134          gIter = gIter->next) {
 135 
 136         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 137 
 138         if (!pcmk__colocation_has_influence(constraint, rsc1)) {
 139             continue;
 140         }
 141         crm_trace("Applying %s to %s", constraint->id, rsc1->id);
 142 
 143         hash1 = pcmk__native_merge_weights(constraint->rsc_lh, rsc1->id, hash1,
 144                                            constraint->node_attribute,
 145                                            constraint->score / (float) INFINITY,
 146                                            pe_weights_positive);
 147     }
 148 
 149     /* Apply rsc2's parental colocations */
 150     for (GList *gIter = rsc2->parent->rsc_cons; gIter != NULL;
 151          gIter = gIter->next) {
 152 
 153         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 154 
 155         crm_trace("Applying %s to %s", constraint->id, rsc2->id);
 156 
 157         hash2 = pcmk__native_merge_weights(constraint->rsc_rh, rsc2->id, hash2,
 158                                            constraint->node_attribute,
 159                                            constraint->score / (float) INFINITY,
 160                                            0);
 161     }
 162 
 163     for (GList *gIter = rsc2->parent->rsc_cons_lhs; gIter;
 164          gIter = gIter->next) {
 165 
 166         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 167 
 168         if (!pcmk__colocation_has_influence(constraint, rsc2)) {
 169             continue;
 170         }
 171         crm_trace("Applying %s to %s", constraint->id, rsc2->id);
 172 
 173         hash2 = pcmk__native_merge_weights(constraint->rsc_lh, rsc2->id, hash2,
 174                                            constraint->node_attribute,
 175                                            constraint->score / (float) INFINITY,
 176                                            pe_weights_positive);
 177     }
 178 
 179     /* Current location score */
 180     node1 = g_hash_table_lookup(hash1, current_node1->details->id);
 181     node2 = g_hash_table_lookup(hash2, current_node2->details->id);
 182 
 183     if (node1->weight < node2->weight) {
 184         if (node1->weight < 0) {
 185             crm_trace("%s > %s: current score: %d %d",
 186                       rsc1->id, rsc2->id, node1->weight, node2->weight);
 187             rc = -1;
 188             goto out;
 189 
 190         } else {
 191             crm_trace("%s < %s: current score: %d %d",
 192                       rsc1->id, rsc2->id, node1->weight, node2->weight);
 193             rc = 1;
 194             goto out;
 195         }
 196 
 197     } else if (node1->weight > node2->weight) {
 198         crm_trace("%s > %s: current score: %d %d",
 199                   rsc1->id, rsc2->id, node1->weight, node2->weight);
 200         rc = -1;
 201         goto out;
 202     }
 203 
 204     /* All location scores */
 205     list1 = g_hash_table_get_values(hash1);
 206     list2 = g_hash_table_get_values(hash2);
 207 
 208     list1 = sort_nodes_by_weight(list1, current_node1, data_set);
 209     list2 = sort_nodes_by_weight(list2, current_node2, data_set);
 210 
 211     for (GList *gIter1 = list1, *gIter2 = list2;
 212          (gIter1 != NULL) && (gIter2 != NULL);
 213          gIter1 = gIter1->next, gIter2 = gIter2->next) {
 214 
 215         node1 = (pe_node_t *) gIter1->data;
 216         node2 = (pe_node_t *) gIter2->data;
 217 
 218         if (node1 == NULL) {
 219             crm_trace("%s < %s: colocated score NULL", rsc1->id, rsc2->id);
 220             rc = 1;
 221             break;
 222 
 223         } else if (node2 == NULL) {
 224             crm_trace("%s > %s: colocated score NULL", rsc1->id, rsc2->id);
 225             rc = -1;
 226             break;
 227         }
 228 
 229         if (node1->weight < node2->weight) {
 230             crm_trace("%s < %s: colocated score", rsc1->id, rsc2->id);
 231             rc = 1;
 232             break;
 233 
 234         } else if (node1->weight > node2->weight) {
 235             crm_trace("%s > %s: colocated score", rsc1->id, rsc2->id);
 236             rc = -1;
 237             break;
 238         }
 239     }
 240 
 241 out:
 242     g_hash_table_destroy(hash1);
 243     g_hash_table_destroy(hash2);
 244     g_list_free(list1);
 245     g_list_free(list2);
 246 
 247     return rc;
 248 }
 249 
 250 gint
 251 sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253     int rc = 0;
 254     pe_node_t *node1 = NULL;
 255     pe_node_t *node2 = NULL;
 256     pe_node_t *current_node1 = NULL;
 257     pe_node_t *current_node2 = NULL;
 258     unsigned int nnodes1 = 0;
 259     unsigned int nnodes2 = 0;
 260 
 261     gboolean can1 = TRUE;
 262     gboolean can2 = TRUE;
 263 
 264     const pe_resource_t *resource1 = (const pe_resource_t *)a;
 265     const pe_resource_t *resource2 = (const pe_resource_t *)b;
 266 
 267     CRM_ASSERT(resource1 != NULL);
 268     CRM_ASSERT(resource2 != NULL);
 269 
 270     /* allocation order:
 271      *  - active instances
 272      *  - instances running on nodes with the least copies
 273      *  - active instances on nodes that can't support them or are to be fenced
 274      *  - failed instances
 275      *  - inactive instances
 276      */
 277 
 278     current_node1 = pe__find_active_on(resource1, &nnodes1, NULL);
 279     current_node2 = pe__find_active_on(resource2, &nnodes2, NULL);
 280 
 281     /* If both instances are running and at least one is multiply
 282      * active, give precedence to the one that's running on fewer nodes.
 283      */
 284     if ((nnodes1 > 0) && (nnodes2 > 0)) {
 285         if (nnodes1 < nnodes2) {
 286             crm_trace("%s < %s: running_on", resource1->id, resource2->id);
 287             return -1;
 288 
 289         } else if (nnodes1 > nnodes2) {
 290             crm_trace("%s > %s: running_on", resource1->id, resource2->id);
 291             return 1;
 292         }
 293     }
 294 
 295     /* Instance whose current location is available sorts first */
 296     node1 = current_node1;
 297     node2 = current_node2;
 298     if (node1 != NULL) {
 299         pe_node_t *match = pe_hash_table_lookup(resource1->allowed_nodes, node1->details->id);
 300 
 301         if (match == NULL || match->weight < 0) {
 302             crm_trace("%s: current location is unavailable", resource1->id);
 303             node1 = NULL;
 304             can1 = FALSE;
 305         }
 306     }
 307 
 308     if (node2 != NULL) {
 309         pe_node_t *match = pe_hash_table_lookup(resource2->allowed_nodes, node2->details->id);
 310 
 311         if (match == NULL || match->weight < 0) {
 312             crm_trace("%s: current location is unavailable", resource2->id);
 313             node2 = NULL;
 314             can2 = FALSE;
 315         }
 316     }
 317 
 318     if (can1 && !can2) {
 319         crm_trace("%s < %s: availability of current location", resource1->id,
 320                   resource2->id);
 321         return -1;
 322 
 323     } else if (!can1 && can2) {
 324         crm_trace("%s > %s: availability of current location", resource1->id,
 325                   resource2->id);
 326         return 1;
 327     }
 328 
 329     /* Higher-priority instance sorts first */
 330     if (resource1->priority > resource2->priority) {
 331         crm_trace("%s < %s: priority", resource1->id, resource2->id);
 332         return -1;
 333 
 334     } else if (resource1->priority < resource2->priority) {
 335         crm_trace("%s > %s: priority", resource1->id, resource2->id);
 336         return 1;
 337     }
 338 
 339     /* Active instance sorts first */
 340     if (node1 == NULL && node2 == NULL) {
 341         crm_trace("%s == %s: not active", resource1->id, resource2->id);
 342         return 0;
 343 
 344     } else if (node1 == NULL) {
 345         crm_trace("%s > %s: active", resource1->id, resource2->id);
 346         return 1;
 347 
 348     } else if (node2 == NULL) {
 349         crm_trace("%s < %s: active", resource1->id, resource2->id);
 350         return -1;
 351     }
 352 
 353     /* Instance whose current node can run resources sorts first */
 354     can1 = can_run_resources(node1);
 355     can2 = can_run_resources(node2);
 356     if (can1 && !can2) {
 357         crm_trace("%s < %s: can", resource1->id, resource2->id);
 358         return -1;
 359 
 360     } else if (!can1 && can2) {
 361         crm_trace("%s > %s: can", resource1->id, resource2->id);
 362         return 1;
 363     }
 364 
 365     /* Is the parent allowed to run on the instance's current node?
 366      * Instance with parent allowed sorts first.
 367      */
 368     node1 = parent_node_instance(resource1, node1);
 369     node2 = parent_node_instance(resource2, node2);
 370     if (node1 == NULL && node2 == NULL) {
 371         crm_trace("%s == %s: not allowed", resource1->id, resource2->id);
 372         return 0;
 373 
 374     } else if (node1 == NULL) {
 375         crm_trace("%s > %s: not allowed", resource1->id, resource2->id);
 376         return 1;
 377 
 378     } else if (node2 == NULL) {
 379         crm_trace("%s < %s: not allowed", resource1->id, resource2->id);
 380         return -1;
 381     }
 382 
 383     /* Does one node have more instances allocated?
 384      * Instance whose current node has fewer instances sorts first.
 385      */
 386     if (node1->count < node2->count) {
 387         crm_trace("%s < %s: count", resource1->id, resource2->id);
 388         return -1;
 389 
 390     } else if (node1->count > node2->count) {
 391         crm_trace("%s > %s: count", resource1->id, resource2->id);
 392         return 1;
 393     }
 394 
 395     /* Failed instance sorts first */
 396     can1 = did_fail(resource1);
 397     can2 = did_fail(resource2);
 398     if (can1 && !can2) {
 399         crm_trace("%s > %s: failed", resource1->id, resource2->id);
 400         return 1;
 401     } else if (!can1 && can2) {
 402         crm_trace("%s < %s: failed", resource1->id, resource2->id);
 403         return -1;
 404     }
 405 
 406     rc = order_instance_by_colocation(resource1, resource2, data_set);
 407     if (rc != 0) {
 408         return rc;
 409     }
 410 
 411     /* Default to lexicographic order by ID */
 412     rc = strcmp(resource1->id, resource2->id);
 413     crm_trace("%s %c %s: default", resource1->id, rc < 0 ? '<' : '>', resource2->id);
 414     return rc;
 415 }
 416 
 417 static pe_node_t *
 418 can_run_instance(pe_resource_t * rsc, pe_node_t * node, int limit)
     /* [previous][next][first][last][top][bottom][index][help] */
 419 {
 420     pe_node_t *local_node = NULL;
 421 
 422     if (node == NULL && rsc->allowed_nodes) {
 423         GHashTableIter iter;
 424         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 425         while (g_hash_table_iter_next(&iter, NULL, (void **)&local_node)) {
 426             can_run_instance(rsc, local_node, limit);
 427         }
 428         return NULL;
 429     }
 430 
 431     if (!node) {
 432         /* make clang analyzer happy */
 433         goto bail;
 434 
 435     } else if (can_run_resources(node) == FALSE) {
 436         goto bail;
 437 
 438     } else if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
 439         goto bail;
 440     }
 441 
 442     local_node = parent_node_instance(rsc, node);
 443 
 444     if (local_node == NULL) {
 445         crm_warn("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
 446         goto bail;
 447 
 448     } else if (local_node->weight < 0) {
 449         common_update_score(rsc, node->details->id, local_node->weight);
 450         pe_rsc_trace(rsc, "%s cannot run on %s: Parent node weight doesn't allow it.",
 451                      rsc->id, node->details->uname);
 452 
 453     } else if (local_node->count < limit) {
 454         pe_rsc_trace(rsc, "%s can run on %s (already running %d)",
 455                      rsc->id, node->details->uname, local_node->count);
 456         return local_node;
 457 
 458     } else {
 459         pe_rsc_trace(rsc, "%s cannot run on %s: node full (%d >= %d)",
 460                      rsc->id, node->details->uname, local_node->count, limit);
 461     }
 462 
 463   bail:
 464     if (node) {
 465         common_update_score(rsc, node->details->id, -INFINITY);
 466     }
 467     return NULL;
 468 }
 469 
 470 static pe_node_t *
 471 allocate_instance(pe_resource_t *rsc, pe_node_t *prefer, gboolean all_coloc,
     /* [previous][next][first][last][top][bottom][index][help] */
 472                   int limit, pe_working_set_t *data_set)
 473 {
 474     pe_node_t *chosen = NULL;
 475     GHashTable *backup = NULL;
 476 
 477     CRM_ASSERT(rsc);
 478     pe_rsc_trace(rsc, "Checking allocation of %s (preferring %s, using %s parent colocations)",
 479                  rsc->id, (prefer? prefer->details->uname: "none"),
 480                  (all_coloc? "all" : "some"));
 481 
 482     if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
 483         return rsc->fns->location(rsc, NULL, FALSE);
 484 
 485     } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 486         pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
 487         return NULL;
 488     }
 489 
 490     /* Only include positive colocation preferences of dependent resources
 491      * if not every node will get a copy of the clone
 492      */
 493     append_parent_colocation(rsc->parent, rsc, all_coloc);
 494 
 495     if (prefer) {
 496         pe_node_t *local_prefer = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
 497 
 498         if (local_prefer == NULL || local_prefer->weight < 0) {
 499             pe_rsc_trace(rsc, "Not pre-allocating %s to %s - unavailable", rsc->id,
 500                          prefer->details->uname);
 501             return NULL;
 502         }
 503     }
 504 
 505     can_run_instance(rsc, NULL, limit);
 506 
 507     backup = pcmk__copy_node_table(rsc->allowed_nodes);
 508     pe_rsc_trace(rsc, "Allocating instance %s", rsc->id);
 509     chosen = rsc->cmds->allocate(rsc, prefer, data_set);
 510     if (chosen && prefer && (chosen->details != prefer->details)) {
 511         crm_info("Not pre-allocating %s to %s because %s is better",
 512                  rsc->id, prefer->details->uname, chosen->details->uname);
 513         g_hash_table_destroy(rsc->allowed_nodes);
 514         rsc->allowed_nodes = backup;
 515         native_deallocate(rsc);
 516         chosen = NULL;
 517         backup = NULL;
 518     }
 519     if (chosen) {
 520         pe_node_t *local_node = parent_node_instance(rsc, chosen);
 521 
 522         if (local_node) {
 523             local_node->count++;
 524 
 525         } else if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 526             /* what to do? we can't enforce per-node limits in this case */
 527             pcmk__config_err("%s not found in %s (list of %d)",
 528                              chosen->details->id, rsc->parent->id,
 529                              g_hash_table_size(rsc->parent->allowed_nodes));
 530         }
 531     }
 532 
 533     if(backup) {
 534         g_hash_table_destroy(backup);
 535     }
 536     return chosen;
 537 }
 538 
 539 static void
 540 append_parent_colocation(pe_resource_t * rsc, pe_resource_t * child, gboolean all)
     /* [previous][next][first][last][top][bottom][index][help] */
 541 {
 542 
 543     GList *gIter = NULL;
 544 
 545     gIter = rsc->rsc_cons;
 546     for (; gIter != NULL; gIter = gIter->next) {
 547         pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
 548 
 549         if (all || cons->score < 0 || cons->score == INFINITY) {
 550             child->rsc_cons = g_list_prepend(child->rsc_cons, cons);
 551         }
 552     }
 553 
 554     gIter = rsc->rsc_cons_lhs;
 555     for (; gIter != NULL; gIter = gIter->next) {
 556         pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter->data;
 557 
 558         if (!pcmk__colocation_has_influence(cons, child)) {
 559            continue;
 560         }
 561         if (all || cons->score < 0) {
 562             child->rsc_cons_lhs = g_list_prepend(child->rsc_cons_lhs, cons);
 563         }
 564     }
 565 }
 566 
 567 
 568 void
 569 distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
 570                     int max, int per_host_max, pe_working_set_t * data_set);
 571 
 572 void
 573 distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
     /* [previous][next][first][last][top][bottom][index][help] */
 574                     int max, int per_host_max, pe_working_set_t * data_set) 
 575 {
 576     int loop_max = 0;
 577     int allocated = 0;
 578     int available_nodes = 0;
 579     bool all_coloc = false;
 580 
 581     /* count now tracks the number of clones currently allocated */
 582     for(GList *nIter = nodes; nIter != NULL; nIter = nIter->next) {
 583         pe_node_t *node = nIter->data;
 584 
 585         node->count = 0;
 586         if (can_run_resources(node)) {
 587             available_nodes++;
 588         }
 589     }
 590 
 591     all_coloc = (max < available_nodes) ? true : false;
 592 
 593     if(available_nodes) {
 594         loop_max = max / available_nodes;
 595     }
 596     if (loop_max < 1) {
 597         loop_max = 1;
 598     }
 599 
 600     pe_rsc_debug(rsc, "Allocating up to %d %s instances to a possible %d nodes (at most %d per host, %d optimal)",
 601                  max, rsc->id, available_nodes, per_host_max, loop_max);
 602 
 603     /* Pre-allocate as many instances as we can to their current location */
 604     for (GList *gIter = children; gIter != NULL && allocated < max; gIter = gIter->next) {
 605         pe_resource_t *child = (pe_resource_t *) gIter->data;
 606         pe_node_t *child_node = NULL;
 607         pe_node_t *local_node = NULL;
 608 
 609         if ((child->running_on == NULL)
 610             || !pcmk_is_set(child->flags, pe_rsc_provisional)
 611             || pcmk_is_set(child->flags, pe_rsc_failed)) {
 612 
 613             continue;
 614         }
 615 
 616         child_node = pe__current_node(child);
 617         local_node = parent_node_instance(child, child_node);
 618 
 619         pe_rsc_trace(rsc,
 620                      "Checking pre-allocation of %s to %s (%d remaining of %d)",
 621                      child->id, child_node->details->uname, max - allocated,
 622                      max);
 623 
 624         if (!can_run_resources(child_node) || (child_node->weight < 0)) {
 625             pe_rsc_trace(rsc, "Not pre-allocating because %s can not run %s",
 626                          child_node->details->uname, child->id);
 627             continue;
 628         }
 629 
 630         if ((local_node != NULL) && (local_node->count >= loop_max)) {
 631             pe_rsc_trace(rsc,
 632                          "Not pre-allocating because %s already allocated "
 633                          "optimal instances", child_node->details->uname);
 634             continue;
 635         }
 636 
 637         if (allocate_instance(child, child_node, all_coloc, per_host_max,
 638                               data_set)) {
 639             pe_rsc_trace(rsc, "Pre-allocated %s to %s", child->id,
 640                          child_node->details->uname);
 641             allocated++;
 642         }
 643     }
 644 
 645     pe_rsc_trace(rsc, "Done pre-allocating (%d of %d)", allocated, max);
 646 
 647     for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
 648         pe_resource_t *child = (pe_resource_t *) gIter->data;
 649 
 650         if (child->running_on != NULL) {
 651             pe_node_t *child_node = pe__current_node(child);
 652             pe_node_t *local_node = parent_node_instance(child, child_node);
 653 
 654             if (local_node == NULL) {
 655                 crm_err("%s is running on %s which isn't allowed",
 656                         child->id, child_node->details->uname);
 657             }
 658         }
 659 
 660         if (!pcmk_is_set(child->flags, pe_rsc_provisional)) {
 661         } else if (allocated >= max) {
 662             pe_rsc_debug(rsc, "Child %s not allocated - limit reached %d %d", child->id, allocated, max);
 663             resource_location(child, NULL, -INFINITY, "clone:limit_reached", data_set);
 664         } else {
 665             if (allocate_instance(child, NULL, all_coloc, per_host_max,
 666                                   data_set)) {
 667                 allocated++;
 668             }
 669         }
 670     }
 671 
 672     pe_rsc_debug(rsc, "Allocated %d %s instances of a possible %d",
 673                  allocated, rsc->id, max);
 674 }
 675 
 676 
 677 pe_node_t *
 678 pcmk__clone_allocate(pe_resource_t *rsc, pe_node_t *prefer,
     /* [previous][next][first][last][top][bottom][index][help] */
 679                      pe_working_set_t *data_set)
 680 {
 681     GList *nodes = NULL;
 682     clone_variant_data_t *clone_data = NULL;
 683 
 684     get_clone_variant_data(clone_data, rsc);
 685 
 686     if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
 687         return NULL;
 688 
 689     } else if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 690         pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
 691         return NULL;
 692     }
 693 
 694     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
 695         pcmk__add_promotion_scores(rsc);
 696     }
 697 
 698     pe__set_resource_flags(rsc, pe_rsc_allocating);
 699 
 700     /* this information is used by sort_clone_instance() when deciding in which 
 701      * order to allocate clone instances
 702      */
 703     for (GList *gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
 704         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 705 
 706         pe_rsc_trace(rsc, "%s: Allocating %s first",
 707                      rsc->id, constraint->rsc_rh->id);
 708         constraint->rsc_rh->cmds->allocate(constraint->rsc_rh, prefer, data_set);
 709     }
 710 
 711     for (GList *gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
 712         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 713 
 714         if (!pcmk__colocation_has_influence(constraint, NULL)) {
 715             continue;
 716         }
 717         rsc->allowed_nodes =
 718             constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id, rsc->allowed_nodes,
 719                                                     constraint->node_attribute,
 720                                                     (float)constraint->score / INFINITY,
 721                                                     (pe_weights_rollback | pe_weights_positive));
 722     }
 723 
 724     pe__show_node_weights(!pcmk_is_set(data_set->flags, pe_flag_show_scores),
 725                           rsc, __func__, rsc->allowed_nodes, data_set);
 726 
 727     nodes = g_hash_table_get_values(rsc->allowed_nodes);
 728     nodes = sort_nodes_by_weight(nodes, NULL, data_set);
 729     rsc->children = g_list_sort_with_data(rsc->children, sort_clone_instance, data_set);
 730     distribute_children(rsc, rsc->children, nodes, clone_data->clone_max, clone_data->clone_node_max, data_set);
 731     g_list_free(nodes);
 732 
 733     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
 734         pcmk__set_instance_roles(rsc, data_set);
 735     }
 736 
 737     pe__clear_resource_flags(rsc, pe_rsc_provisional|pe_rsc_allocating);
 738     pe_rsc_trace(rsc, "Done allocating %s", rsc->id);
 739     return NULL;
 740 }
 741 
 742 static void
 743 clone_update_pseudo_status(pe_resource_t * rsc, gboolean * stopping, gboolean * starting,
     /* [previous][next][first][last][top][bottom][index][help] */
 744                            gboolean * active)
 745 {
 746     GList *gIter = NULL;
 747 
 748     if (rsc->children) {
 749 
 750         gIter = rsc->children;
 751         for (; gIter != NULL; gIter = gIter->next) {
 752             pe_resource_t *child = (pe_resource_t *) gIter->data;
 753 
 754             clone_update_pseudo_status(child, stopping, starting, active);
 755         }
 756 
 757         return;
 758     }
 759 
 760     CRM_ASSERT(active != NULL);
 761     CRM_ASSERT(starting != NULL);
 762     CRM_ASSERT(stopping != NULL);
 763 
 764     if (rsc->running_on) {
 765         *active = TRUE;
 766     }
 767 
 768     gIter = rsc->actions;
 769     for (; gIter != NULL; gIter = gIter->next) {
 770         pe_action_t *action = (pe_action_t *) gIter->data;
 771 
 772         if (*starting && *stopping) {
 773             return;
 774 
 775         } else if (pcmk_is_set(action->flags, pe_action_optional)) {
 776             pe_rsc_trace(rsc, "Skipping optional: %s", action->uuid);
 777             continue;
 778 
 779         } else if (!pcmk_any_flags_set(action->flags,
 780                                        pe_action_pseudo|pe_action_runnable)) {
 781             pe_rsc_trace(rsc, "Skipping unrunnable: %s", action->uuid);
 782             continue;
 783 
 784         } else if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_casei)) {
 785             pe_rsc_trace(rsc, "Stopping due to: %s", action->uuid);
 786             *stopping = TRUE;
 787 
 788         } else if (pcmk__str_eq(RSC_START, action->task, pcmk__str_casei)) {
 789             if (!pcmk_is_set(action->flags, pe_action_runnable)) {
 790                 pe_rsc_trace(rsc, "Skipping pseudo-op: %s run=%d, pseudo=%d",
 791                              action->uuid,
 792                              pcmk_is_set(action->flags, pe_action_runnable),
 793                              pcmk_is_set(action->flags, pe_action_pseudo));
 794             } else {
 795                 pe_rsc_trace(rsc, "Starting due to: %s", action->uuid);
 796                 pe_rsc_trace(rsc, "%s run=%d, pseudo=%d",
 797                              action->uuid,
 798                              pcmk_is_set(action->flags, pe_action_runnable),
 799                              pcmk_is_set(action->flags, pe_action_pseudo));
 800                 *starting = TRUE;
 801             }
 802         }
 803     }
 804 }
 805 
 806 static pe_action_t *
 807 find_rsc_action(pe_resource_t *rsc, const char *task, gboolean active_only,
     /* [previous][next][first][last][top][bottom][index][help] */
 808                 GList **list)
 809 {
 810     pe_action_t *match = NULL;
 811     GList *possible = NULL;
 812     GList *active = NULL;
 813 
 814     possible = pe__resource_actions(rsc, NULL, task, FALSE);
 815 
 816     if (active_only) {
 817         GList *gIter = possible;
 818 
 819         for (; gIter != NULL; gIter = gIter->next) {
 820             pe_action_t *op = (pe_action_t *) gIter->data;
 821 
 822             if (!pcmk_is_set(op->flags, pe_action_optional)) {
 823                 active = g_list_prepend(active, op);
 824             }
 825         }
 826 
 827         if (active && pcmk__list_of_1(active)) {
 828             match = g_list_nth_data(active, 0);
 829         }
 830 
 831         if (list) {
 832             *list = active;
 833             active = NULL;
 834         }
 835 
 836     } else if (possible && pcmk__list_of_1(possible)) {
 837         match = g_list_nth_data(possible, 0);
 838 
 839     }
 840     if (list) {
 841         *list = possible;
 842         possible = NULL;
 843     }
 844 
 845     if (possible) {
 846         g_list_free(possible);
 847     }
 848     if (active) {
 849         g_list_free(active);
 850     }
 851 
 852     return match;
 853 }
 854 
 855 static void
 856 child_ordering_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 857 {
 858     pe_action_t *stop = NULL;
 859     pe_action_t *start = NULL;
 860     pe_action_t *last_stop = NULL;
 861     pe_action_t *last_start = NULL;
 862     GList *gIter = NULL;
 863     gboolean active_only = TRUE;        /* change to false to get the old behavior */
 864     clone_variant_data_t *clone_data = NULL;
 865 
 866     get_clone_variant_data(clone_data, rsc);
 867 
 868     if (clone_data->ordered == FALSE) {
 869         return;
 870     }
 871     /* we have to maintain a consistent sorted child list when building order constraints */
 872     rsc->children = g_list_sort(rsc->children, sort_rsc_id);
 873 
 874     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 875         pe_resource_t *child = (pe_resource_t *) gIter->data;
 876 
 877         stop = find_rsc_action(child, RSC_STOP, active_only, NULL);
 878         if (stop) {
 879             if (last_stop) {
 880                 /* child/child relative stop */
 881                 order_actions(stop, last_stop, pe_order_optional);
 882             }
 883             last_stop = stop;
 884         }
 885 
 886         start = find_rsc_action(child, RSC_START, active_only, NULL);
 887         if (start) {
 888             if (last_start) {
 889                 /* child/child relative start */
 890                 order_actions(last_start, start, pe_order_optional);
 891             }
 892             last_start = start;
 893         }
 894     }
 895 }
 896 
 897 void
 898 clone_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 899 {
 900     clone_variant_data_t *clone_data = NULL;
 901 
 902     get_clone_variant_data(clone_data, rsc);
 903     clone_create_pseudo_actions(rsc, rsc->children, &clone_data->start_notify, &clone_data->stop_notify,data_set);
 904     child_ordering_constraints(rsc, data_set);
 905     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
 906         create_promotable_actions(rsc, data_set);
 907     }
 908 }
 909 
 910 void
 911 clone_create_pseudo_actions(
     /* [previous][next][first][last][top][bottom][index][help] */
 912     pe_resource_t * rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify,  pe_working_set_t * data_set)
 913 {
 914     gboolean child_active = FALSE;
 915     gboolean child_starting = FALSE;
 916     gboolean child_stopping = FALSE;
 917     gboolean allow_dependent_migrations = TRUE;
 918 
 919     pe_action_t *stop = NULL;
 920     pe_action_t *stopped = NULL;
 921 
 922     pe_action_t *start = NULL;
 923     pe_action_t *started = NULL;
 924 
 925     pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
 926 
 927     for (GList *gIter = children; gIter != NULL; gIter = gIter->next) {
 928         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 929         gboolean starting = FALSE;
 930         gboolean stopping = FALSE;
 931 
 932         child_rsc->cmds->create_actions(child_rsc, data_set);
 933         clone_update_pseudo_status(child_rsc, &stopping, &starting, &child_active);
 934         if (stopping && starting) {
 935             allow_dependent_migrations = FALSE;
 936         }
 937 
 938         child_stopping |= stopping;
 939         child_starting |= starting;
 940     }
 941 
 942     /* start */
 943     start = create_pseudo_resource_op(rsc, RSC_START, !child_starting, TRUE, data_set);
 944     started = create_pseudo_resource_op(rsc, RSC_STARTED, !child_starting, FALSE, data_set);
 945     started->priority = INFINITY;
 946 
 947     if (child_active || child_starting) {
 948         pe__set_action_flags(started, pe_action_runnable);
 949     }
 950 
 951     if (start_notify != NULL && *start_notify == NULL) {
 952         *start_notify = create_notification_boundaries(rsc, RSC_START, start, started, data_set);
 953     }
 954 
 955     /* stop */
 956     stop = create_pseudo_resource_op(rsc, RSC_STOP, !child_stopping, TRUE, data_set);
 957     stopped = create_pseudo_resource_op(rsc, RSC_STOPPED, !child_stopping, TRUE, data_set);
 958     stopped->priority = INFINITY;
 959     if (allow_dependent_migrations) {
 960         pe__set_action_flags(stop, pe_action_migrate_runnable);
 961     }
 962 
 963     if (stop_notify != NULL && *stop_notify == NULL) {
 964         *stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
 965 
 966         if (start_notify && *start_notify && *stop_notify) {
 967             order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
 968         }
 969     }
 970 }
 971 
 972 void
 973 clone_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 974 {
 975     pe_resource_t *last_rsc = NULL;
 976     GList *gIter;
 977     clone_variant_data_t *clone_data = NULL;
 978 
 979     get_clone_variant_data(clone_data, rsc);
 980 
 981     pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
 982     new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
 983     new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
 984     new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
 985 
 986     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
 987         new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
 988         new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set);
 989     }
 990 
 991     if (clone_data->ordered) {
 992         /* we have to maintain a consistent sorted child list when building order constraints */
 993         rsc->children = g_list_sort(rsc->children, sort_rsc_id);
 994     }
 995     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 996         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 997 
 998         child_rsc->cmds->internal_constraints(child_rsc, data_set);
 999 
1000         order_start_start(rsc, child_rsc, pe_order_runnable_left | pe_order_implies_first_printed);
1001         new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed,
1002                       data_set);
1003         if (clone_data->ordered && last_rsc) {
1004             order_start_start(last_rsc, child_rsc, pe_order_optional);
1005         }
1006 
1007         order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed);
1008         new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed,
1009                       data_set);
1010         if (clone_data->ordered && last_rsc) {
1011             order_stop_stop(child_rsc, last_rsc, pe_order_optional);
1012         }
1013 
1014         last_rsc = child_rsc;
1015     }
1016     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1017         promotable_constraints(rsc, data_set);
1018     }
1019 }
1020 
1021 bool
1022 assign_node(pe_resource_t * rsc, pe_node_t * node, gboolean force)
     /* [previous][next][first][last][top][bottom][index][help] */
1023 {
1024     bool changed = FALSE;
1025 
1026     if (rsc->children) {
1027 
1028         for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1029             pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1030 
1031             changed |= assign_node(child_rsc, node, force);
1032         }
1033 
1034         return changed;
1035     }
1036 
1037     if (rsc->allocated_to != NULL) {
1038         changed = true;
1039     }
1040 
1041     native_assign_node(rsc, node, force);
1042     return changed;
1043 }
1044 
1045 gboolean
1046 is_child_compatible(pe_resource_t *child_rsc, pe_node_t * local_node, enum rsc_role_e filter, gboolean current) 
     /* [previous][next][first][last][top][bottom][index][help] */
1047 {
1048     pe_node_t *node = NULL;
1049     enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
1050 
1051     CRM_CHECK(child_rsc && local_node, return FALSE);
1052     if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1053         /* We only want instances that haven't failed */
1054         node = child_rsc->fns->location(child_rsc, NULL, current);
1055     }
1056 
1057     if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
1058         crm_trace("Filtered %s", child_rsc->id);
1059         return FALSE;
1060     }
1061 
1062     if (node && (node->details == local_node->details)) {
1063         return TRUE;
1064 
1065     } else if (node) {
1066         crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
1067                   local_node->details->uname);
1068 
1069     } else {
1070         crm_trace("%s - not allocated %d", child_rsc->id, current);
1071     }
1072     return FALSE;
1073 }
1074 
1075 pe_resource_t *
1076 find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
1077                       enum rsc_role_e filter, gboolean current,
1078                       pe_working_set_t *data_set)
1079 {
1080     pe_resource_t *pair = NULL;
1081     GList *gIter = NULL;
1082     GList *scratch = NULL;
1083     pe_node_t *local_node = NULL;
1084 
1085     local_node = local_child->fns->location(local_child, NULL, current);
1086     if (local_node) {
1087         return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
1088     }
1089 
1090     scratch = g_hash_table_get_values(local_child->allowed_nodes);
1091     scratch = sort_nodes_by_weight(scratch, NULL, data_set);
1092 
1093     gIter = scratch;
1094     for (; gIter != NULL; gIter = gIter->next) {
1095         pe_node_t *node = (pe_node_t *) gIter->data;
1096 
1097         pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
1098         if (pair) {
1099             goto done;
1100         }
1101     }
1102 
1103     pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
1104   done:
1105     g_list_free(scratch);
1106     return pair;
1107 }
1108 
1109 void
1110 clone_rsc_colocation_lh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
     /* [previous][next][first][last][top][bottom][index][help] */
1111                         pcmk__colocation_t *constraint,
1112                         pe_working_set_t *data_set)
1113 {
1114     /* -- Never called --
1115      *
1116      * Instead we add the colocation constraints to the child and call from there
1117      */
1118     CRM_ASSERT(FALSE);
1119 }
1120 
1121 void
1122 clone_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
     /* [previous][next][first][last][top][bottom][index][help] */
1123                         pcmk__colocation_t *constraint,
1124                         pe_working_set_t *data_set)
1125 {
1126     GList *gIter = NULL;
1127     gboolean do_interleave = FALSE;
1128     const char *interleave_s = NULL;
1129 
1130     CRM_CHECK(constraint != NULL, return);
1131     CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
1132     CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
1133     CRM_CHECK(rsc_lh->variant == pe_native, return);
1134 
1135     pe_rsc_trace(rsc_rh, "Processing constraint %s: %s -> %s %d",
1136                  constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);
1137 
1138     if (pcmk_is_set(rsc_rh->flags, pe_rsc_promotable)) {
1139         if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1140             pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1141             return;
1142         } else if (constraint->role_rh == RSC_ROLE_UNKNOWN) {
1143             pe_rsc_trace(rsc_rh, "Handling %s as a clone colocation", constraint->id);
1144         } else {
1145             promotable_colocation_rh(rsc_lh, rsc_rh, constraint, data_set);
1146             return;
1147         }
1148     }
1149 
1150     /* only the LHS side needs to be labeled as interleave */
1151     interleave_s = g_hash_table_lookup(constraint->rsc_lh->meta, XML_RSC_ATTR_INTERLEAVE);
1152     if(crm_is_true(interleave_s) && constraint->rsc_lh->variant > pe_group) {
1153         // TODO: Do we actually care about multiple RH copies sharing a LH copy anymore?
1154         if (copies_per_node(constraint->rsc_lh) != copies_per_node(constraint->rsc_rh)) {
1155             pcmk__config_err("Cannot interleave %s and %s because they do not "
1156                              "support the same number of instances per node",
1157                              constraint->rsc_lh->id, constraint->rsc_rh->id);
1158 
1159         } else {
1160             do_interleave = TRUE;
1161         }
1162     }
1163 
1164     if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1165         pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1166         return;
1167 
1168     } else if (do_interleave) {
1169         pe_resource_t *rh_child = NULL;
1170 
1171         rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN,
1172                                          FALSE, data_set);
1173 
1174         if (rh_child) {
1175             pe_rsc_debug(rsc_rh, "Pairing %s with %s", rsc_lh->id, rh_child->id);
1176             rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint,
1177                                             data_set);
1178 
1179         } else if (constraint->score >= INFINITY) {
1180             crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1181             assign_node(rsc_lh, NULL, TRUE);
1182 
1183         } else {
1184             pe_rsc_debug(rsc_rh, "Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1185         }
1186 
1187         return;
1188 
1189     } else if (constraint->score >= INFINITY) {
1190         GList *rhs = NULL;
1191 
1192         gIter = rsc_rh->children;
1193         for (; gIter != NULL; gIter = gIter->next) {
1194             pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1195             pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1196 
1197             if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1198                 pe_rsc_trace(rsc_rh, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
1199                 rhs = g_list_prepend(rhs, chosen);
1200             }
1201         }
1202 
1203         node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
1204         g_list_free(rhs);
1205         return;
1206     }
1207 
1208     gIter = rsc_rh->children;
1209     for (; gIter != NULL; gIter = gIter->next) {
1210         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1211 
1212         child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint,
1213                                            data_set);
1214     }
1215 }
1216 
1217 enum action_tasks
1218 clone_child_action(pe_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
1219 {
1220     enum action_tasks result = no_action;
1221     pe_resource_t *child = (pe_resource_t *) action->rsc->children->data;
1222 
1223     if (pcmk__strcase_any_of(action->task, "notify", "notified", NULL)) {
1224 
1225         /* Find the action we're notifying about instead */
1226 
1227         int stop = 0;
1228         char *key = action->uuid;
1229         int lpc = strlen(key);
1230 
1231         for (; lpc > 0; lpc--) {
1232             if (key[lpc] == '_' && stop == 0) {
1233                 stop = lpc;
1234 
1235             } else if (key[lpc] == '_') {
1236                 char *task_mutable = NULL;
1237 
1238                 lpc++;
1239                 task_mutable = strdup(key + lpc);
1240                 task_mutable[stop - lpc] = 0;
1241 
1242                 crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
1243                 result = get_complex_task(child, task_mutable, TRUE);
1244                 free(task_mutable);
1245                 break;
1246             }
1247         }
1248 
1249     } else {
1250         result = get_complex_task(child, action->task, TRUE);
1251     }
1252     return result;
1253 }
1254 
1255 #define pe__clear_action_summary_flags(flags, action, flag) do {        \
1256         flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,     \
1257                                      "Action summary", action->rsc->id, \
1258                                      flags, flag, #flag);               \
1259     } while (0)
1260 
1261 enum pe_action_flags
1262 summary_action_flags(pe_action_t * action, GList *children, pe_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
1263 {
1264     GList *gIter = NULL;
1265     gboolean any_runnable = FALSE;
1266     gboolean check_runnable = TRUE;
1267     enum action_tasks task = clone_child_action(action);
1268     enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
1269     const char *task_s = task2text(task);
1270 
1271     for (gIter = children; gIter != NULL; gIter = gIter->next) {
1272         pe_action_t *child_action = NULL;
1273         pe_resource_t *child = (pe_resource_t *) gIter->data;
1274 
1275         child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
1276         pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
1277                      node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
1278         if (child_action) {
1279             enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
1280 
1281             if (pcmk_is_set(flags, pe_action_optional)
1282                 && !pcmk_is_set(child_flags, pe_action_optional)) {
1283                 pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
1284                              child_action->uuid);
1285                 pe__clear_action_summary_flags(flags, action, pe_action_optional);
1286                 pe__clear_action_flags(action, pe_action_optional);
1287             }
1288             if (pcmk_is_set(child_flags, pe_action_runnable)) {
1289                 any_runnable = TRUE;
1290             }
1291         }
1292     }
1293 
1294     if (check_runnable && any_runnable == FALSE) {
1295         pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
1296         pe__clear_action_summary_flags(flags, action, pe_action_runnable);
1297         if (node == NULL) {
1298             pe__clear_action_flags(action, pe_action_runnable);
1299         }
1300     }
1301 
1302     return flags;
1303 }
1304 
1305 enum pe_action_flags
1306 clone_action_flags(pe_action_t * action, pe_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
1307 {
1308     return summary_action_flags(action, action->rsc->children, node);
1309 }
1310 
1311 void
1312 clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
     /* [previous][next][first][last][top][bottom][index][help] */
1313 {
1314     GList *gIter = rsc->children;
1315 
1316     pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
1317 
1318     native_rsc_location(rsc, constraint);
1319 
1320     for (; gIter != NULL; gIter = gIter->next) {
1321         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1322 
1323         child_rsc->cmds->rsc_location(child_rsc, constraint);
1324     }
1325 }
1326 
1327 void
1328 clone_expand(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1329 {
1330     GList *gIter = NULL;
1331     clone_variant_data_t *clone_data = NULL;
1332 
1333     get_clone_variant_data(clone_data, rsc);
1334 
1335     gIter = rsc->actions;
1336     for (; gIter != NULL; gIter = gIter->next) {
1337         pe_action_t *op = (pe_action_t *) gIter->data;
1338 
1339         rsc->cmds->action_flags(op, NULL);
1340     }
1341 
1342     if (clone_data->start_notify) {
1343         collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
1344         pcmk__create_notification_keys(rsc, clone_data->start_notify, data_set);
1345         create_notifications(rsc, clone_data->start_notify, data_set);
1346     }
1347 
1348     if (clone_data->stop_notify) {
1349         collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
1350         pcmk__create_notification_keys(rsc, clone_data->stop_notify, data_set);
1351         create_notifications(rsc, clone_data->stop_notify, data_set);
1352     }
1353 
1354     if (clone_data->promote_notify) {
1355         collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
1356         pcmk__create_notification_keys(rsc, clone_data->promote_notify, data_set);
1357         create_notifications(rsc, clone_data->promote_notify, data_set);
1358     }
1359 
1360     if (clone_data->demote_notify) {
1361         collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
1362         pcmk__create_notification_keys(rsc, clone_data->demote_notify, data_set);
1363         create_notifications(rsc, clone_data->demote_notify, data_set);
1364     }
1365 
1366     /* Now that the notifcations have been created we can expand the children */
1367 
1368     gIter = rsc->children;
1369     for (; gIter != NULL; gIter = gIter->next) {
1370         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1371 
1372         child_rsc->cmds->expand(child_rsc, data_set);
1373     }
1374 
1375     native_expand(rsc, data_set);
1376 
1377     /* The notifications are in the graph now, we can destroy the notify_data */
1378     free_notification_data(clone_data->demote_notify);
1379     clone_data->demote_notify = NULL;
1380     free_notification_data(clone_data->stop_notify);
1381     clone_data->stop_notify = NULL;
1382     free_notification_data(clone_data->start_notify);
1383     clone_data->start_notify = NULL;
1384     free_notification_data(clone_data->promote_notify);
1385     clone_data->promote_notify = NULL;
1386 }
1387 
1388 // Check whether a resource or any of its children is known on node
1389 static bool
1390 rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1391 {
1392     if (rsc->children) {
1393         for (GList *child_iter = rsc->children; child_iter != NULL;
1394              child_iter = child_iter->next) {
1395 
1396             pe_resource_t *child = (pe_resource_t *) child_iter->data;
1397 
1398             if (rsc_known_on(child, node)) {
1399                 return TRUE;
1400             }
1401         }
1402 
1403     } else if (rsc->known_on) {
1404         GHashTableIter iter;
1405         pe_node_t *known_node = NULL;
1406 
1407         g_hash_table_iter_init(&iter, rsc->known_on);
1408         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
1409             if (node->details == known_node->details) {
1410                 return TRUE;
1411             }
1412         }
1413     }
1414     return FALSE;
1415 }
1416 
1417 // Look for an instance of clone that is known on node
1418 static pe_resource_t *
1419 find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1420 {
1421     for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
1422         pe_resource_t *child = (pe_resource_t *) gIter->data;
1423 
1424         if (rsc_known_on(child, node)) {
1425             return child;
1426         }
1427     }
1428     return NULL;
1429 }
1430 
1431 // For unique clones, probe each instance separately
1432 static gboolean
1433 probe_unique_clone(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete,
     /* [previous][next][first][last][top][bottom][index][help] */
1434                    gboolean force, pe_working_set_t *data_set)
1435 {
1436     gboolean any_created = FALSE;
1437 
1438     for (GList *child_iter = rsc->children; child_iter != NULL;
1439          child_iter = child_iter->next) {
1440 
1441         pe_resource_t *child = (pe_resource_t *) child_iter->data;
1442 
1443         any_created |= child->cmds->create_probe(child, node, complete, force,
1444                                                  data_set);
1445     }
1446     return any_created;
1447 }
1448 
1449 // For anonymous clones, only a single instance needs to be probed
1450 static gboolean
1451 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
1452                       pe_action_t *complete, gboolean force,
1453                       pe_working_set_t *data_set)
1454 {
1455     // First, check if we probed an instance on this node last time
1456     pe_resource_t *child = find_instance_on(rsc, node);
1457 
1458     // Otherwise, check if we plan to start an instance on this node
1459     if (child == NULL) {
1460         for (GList *child_iter = rsc->children; child_iter && !child;
1461              child_iter = child_iter->next) {
1462 
1463             pe_node_t *local_node = NULL;
1464             pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
1465 
1466             if (child_rsc) { /* make clang analyzer happy */
1467                 local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1468                 if (local_node && (local_node->details == node->details)) {
1469                     child = child_rsc;
1470                 }
1471             }
1472         }
1473     }
1474 
1475     // Otherwise, use the first clone instance
1476     if (child == NULL) {
1477         child = rsc->children->data;
1478     }
1479     CRM_ASSERT(child);
1480     return child->cmds->create_probe(child, node, complete, force, data_set);
1481 }
1482 
1483 gboolean
1484 clone_create_probe(pe_resource_t * rsc, pe_node_t * node, pe_action_t * complete,
     /* [previous][next][first][last][top][bottom][index][help] */
1485                    gboolean force, pe_working_set_t * data_set)
1486 {
1487     gboolean any_created = FALSE;
1488 
1489     CRM_ASSERT(rsc);
1490 
1491     rsc->children = g_list_sort(rsc->children, sort_rsc_id);
1492     if (rsc->children == NULL) {
1493         pe_warn("Clone %s has no children", rsc->id);
1494         return FALSE;
1495     }
1496 
1497     if (rsc->exclusive_discover) {
1498         pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1499         if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1500             /* exclusive discover is enabled and this node is not marked
1501              * as a node this resource should be discovered on
1502              *
1503              * remove the node from allowed_nodes so that the
1504              * notification contains only nodes that we might ever run
1505              * on
1506              */
1507             g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1508 
1509             /* Bit of a shortcut - might as well take it */
1510             return FALSE;
1511         }
1512     }
1513 
1514     if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1515         any_created = probe_unique_clone(rsc, node, complete, force, data_set);
1516     } else {
1517         any_created = probe_anonymous_clone(rsc, node, complete, force,
1518                                             data_set);
1519     }
1520     return any_created;
1521 }
1522 
1523 void
1524 clone_append_meta(pe_resource_t * rsc, xmlNode * xml)
     /* [previous][next][first][last][top][bottom][index][help] */
1525 {
1526     char *name = NULL;
1527     clone_variant_data_t *clone_data = NULL;
1528 
1529     get_clone_variant_data(clone_data, rsc);
1530 
1531     name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
1532     crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1533     free(name);
1534 
1535     name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
1536     crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1537     free(name);
1538 
1539     name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
1540     crm_xml_add_int(xml, name, clone_data->clone_max);
1541     free(name);
1542 
1543     name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
1544     crm_xml_add_int(xml, name, clone_data->clone_node_max);
1545     free(name);
1546 
1547     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1548         name = crm_meta_name(XML_RSC_ATTR_PROMOTED_MAX);
1549         crm_xml_add_int(xml, name, clone_data->promoted_max);
1550         free(name);
1551 
1552         name = crm_meta_name(XML_RSC_ATTR_PROMOTED_NODEMAX);
1553         crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1554         free(name);
1555 
1556         /* @COMPAT Maintain backward compatibility with resource agents that
1557          * expect the old names (deprecated since 2.0.0).
1558          */
1559         name = crm_meta_name(PCMK_XE_PROMOTED_MAX_LEGACY);
1560         crm_xml_add_int(xml, name, clone_data->promoted_max);
1561         free(name);
1562 
1563         name = crm_meta_name(PCMK_XE_PROMOTED_NODE_MAX_LEGACY);
1564         crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1565         free(name);
1566     }
1567 }

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