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         update_action_flags(started, pe_action_runnable, __func__, __LINE__);
 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         update_action_flags(stop, pe_action_migrate_runnable, __func__,
 961                             __LINE__);
 962     }
 963 
 964     if (stop_notify != NULL && *stop_notify == NULL) {
 965         *stop_notify = create_notification_boundaries(rsc, RSC_STOP, stop, stopped, data_set);
 966 
 967         if (start_notify && *start_notify && *stop_notify) {
 968             order_actions((*stop_notify)->post_done, (*start_notify)->pre, pe_order_optional);
 969         }
 970     }
 971 }
 972 
 973 void
 974 clone_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 975 {
 976     pe_resource_t *last_rsc = NULL;
 977     GList *gIter;
 978     clone_variant_data_t *clone_data = NULL;
 979 
 980     get_clone_variant_data(clone_data, rsc);
 981 
 982     pe_rsc_trace(rsc, "Internal constraints for %s", rsc->id);
 983     new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
 984     new_rsc_order(rsc, RSC_START, rsc, RSC_STARTED, pe_order_runnable_left, data_set);
 985     new_rsc_order(rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_runnable_left, data_set);
 986 
 987     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
 988         new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
 989         new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_runnable_left, data_set);
 990     }
 991 
 992     if (clone_data->ordered) {
 993         /* we have to maintain a consistent sorted child list when building order constraints */
 994         rsc->children = g_list_sort(rsc->children, sort_rsc_id);
 995     }
 996     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 997         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 998 
 999         child_rsc->cmds->internal_constraints(child_rsc, data_set);
1000 
1001         order_start_start(rsc, child_rsc, pe_order_runnable_left | pe_order_implies_first_printed);
1002         new_rsc_order(child_rsc, RSC_START, rsc, RSC_STARTED, pe_order_implies_then_printed,
1003                       data_set);
1004         if (clone_data->ordered && last_rsc) {
1005             order_start_start(last_rsc, child_rsc, pe_order_optional);
1006         }
1007 
1008         order_stop_stop(rsc, child_rsc, pe_order_implies_first_printed);
1009         new_rsc_order(child_rsc, RSC_STOP, rsc, RSC_STOPPED, pe_order_implies_then_printed,
1010                       data_set);
1011         if (clone_data->ordered && last_rsc) {
1012             order_stop_stop(child_rsc, last_rsc, pe_order_optional);
1013         }
1014 
1015         last_rsc = child_rsc;
1016     }
1017     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1018         promotable_constraints(rsc, data_set);
1019     }
1020 }
1021 
1022 bool
1023 assign_node(pe_resource_t * rsc, pe_node_t * node, gboolean force)
     /* [previous][next][first][last][top][bottom][index][help] */
1024 {
1025     bool changed = FALSE;
1026 
1027     if (rsc->children) {
1028 
1029         for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1030             pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1031 
1032             changed |= assign_node(child_rsc, node, force);
1033         }
1034 
1035         return changed;
1036     }
1037 
1038     if (rsc->allocated_to != NULL) {
1039         changed = true;
1040     }
1041 
1042     native_assign_node(rsc, node, force);
1043     return changed;
1044 }
1045 
1046 gboolean
1047 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] */
1048 {
1049     pe_node_t *node = NULL;
1050     enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, current);
1051 
1052     CRM_CHECK(child_rsc && local_node, return FALSE);
1053     if (is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1054         /* We only want instances that haven't failed */
1055         node = child_rsc->fns->location(child_rsc, NULL, current);
1056     }
1057 
1058     if (filter != RSC_ROLE_UNKNOWN && next_role != filter) {
1059         crm_trace("Filtered %s", child_rsc->id);
1060         return FALSE;
1061     }
1062 
1063     if (node && (node->details == local_node->details)) {
1064         return TRUE;
1065 
1066     } else if (node) {
1067         crm_trace("%s - %s vs %s", child_rsc->id, node->details->uname,
1068                   local_node->details->uname);
1069 
1070     } else {
1071         crm_trace("%s - not allocated %d", child_rsc->id, current);
1072     }
1073     return FALSE;
1074 }
1075 
1076 pe_resource_t *
1077 find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
1078                       enum rsc_role_e filter, gboolean current,
1079                       pe_working_set_t *data_set)
1080 {
1081     pe_resource_t *pair = NULL;
1082     GList *gIter = NULL;
1083     GList *scratch = NULL;
1084     pe_node_t *local_node = NULL;
1085 
1086     local_node = local_child->fns->location(local_child, NULL, current);
1087     if (local_node) {
1088         return find_compatible_child_by_node(local_child, local_node, rsc, filter, current);
1089     }
1090 
1091     scratch = g_hash_table_get_values(local_child->allowed_nodes);
1092     scratch = sort_nodes_by_weight(scratch, NULL, data_set);
1093 
1094     gIter = scratch;
1095     for (; gIter != NULL; gIter = gIter->next) {
1096         pe_node_t *node = (pe_node_t *) gIter->data;
1097 
1098         pair = find_compatible_child_by_node(local_child, node, rsc, filter, current);
1099         if (pair) {
1100             goto done;
1101         }
1102     }
1103 
1104     pe_rsc_debug(rsc, "Can't pair %s with %s", local_child->id, rsc->id);
1105   done:
1106     g_list_free(scratch);
1107     return pair;
1108 }
1109 
1110 void
1111 clone_rsc_colocation_lh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
     /* [previous][next][first][last][top][bottom][index][help] */
1112                         pcmk__colocation_t *constraint,
1113                         pe_working_set_t *data_set)
1114 {
1115     /* -- Never called --
1116      *
1117      * Instead we add the colocation constraints to the child and call from there
1118      */
1119     CRM_ASSERT(FALSE);
1120 }
1121 
1122 void
1123 clone_rsc_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
     /* [previous][next][first][last][top][bottom][index][help] */
1124                         pcmk__colocation_t *constraint,
1125                         pe_working_set_t *data_set)
1126 {
1127     GList *gIter = NULL;
1128     gboolean do_interleave = FALSE;
1129     const char *interleave_s = NULL;
1130 
1131     CRM_CHECK(constraint != NULL, return);
1132     CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
1133     CRM_CHECK(rsc_rh != NULL, pe_err("rsc_rh was NULL for %s", constraint->id); return);
1134     CRM_CHECK(rsc_lh->variant == pe_native, return);
1135 
1136     pe_rsc_trace(rsc_rh, "Processing constraint %s: %s -> %s %d",
1137                  constraint->id, rsc_lh->id, rsc_rh->id, constraint->score);
1138 
1139     if (pcmk_is_set(rsc_rh->flags, pe_rsc_promotable)) {
1140         if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1141             pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1142             return;
1143         } else if (constraint->role_rh == RSC_ROLE_UNKNOWN) {
1144             pe_rsc_trace(rsc_rh, "Handling %s as a clone colocation", constraint->id);
1145         } else {
1146             promotable_colocation_rh(rsc_lh, rsc_rh, constraint, data_set);
1147             return;
1148         }
1149     }
1150 
1151     /* only the LHS side needs to be labeled as interleave */
1152     interleave_s = g_hash_table_lookup(constraint->rsc_lh->meta, XML_RSC_ATTR_INTERLEAVE);
1153     if(crm_is_true(interleave_s) && constraint->rsc_lh->variant > pe_group) {
1154         // TODO: Do we actually care about multiple RH copies sharing a LH copy anymore?
1155         if (copies_per_node(constraint->rsc_lh) != copies_per_node(constraint->rsc_rh)) {
1156             pcmk__config_err("Cannot interleave %s and %s because they do not "
1157                              "support the same number of instances per node",
1158                              constraint->rsc_lh->id, constraint->rsc_rh->id);
1159 
1160         } else {
1161             do_interleave = TRUE;
1162         }
1163     }
1164 
1165     if (pcmk_is_set(rsc_rh->flags, pe_rsc_provisional)) {
1166         pe_rsc_trace(rsc_rh, "%s is still provisional", rsc_rh->id);
1167         return;
1168 
1169     } else if (do_interleave) {
1170         pe_resource_t *rh_child = NULL;
1171 
1172         rh_child = find_compatible_child(rsc_lh, rsc_rh, RSC_ROLE_UNKNOWN,
1173                                          FALSE, data_set);
1174 
1175         if (rh_child) {
1176             pe_rsc_debug(rsc_rh, "Pairing %s with %s", rsc_lh->id, rh_child->id);
1177             rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint,
1178                                             data_set);
1179 
1180         } else if (constraint->score >= INFINITY) {
1181             crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1182             assign_node(rsc_lh, NULL, TRUE);
1183 
1184         } else {
1185             pe_rsc_debug(rsc_rh, "Cannot pair %s with instance of %s", rsc_lh->id, rsc_rh->id);
1186         }
1187 
1188         return;
1189 
1190     } else if (constraint->score >= INFINITY) {
1191         GList *rhs = NULL;
1192 
1193         gIter = rsc_rh->children;
1194         for (; gIter != NULL; gIter = gIter->next) {
1195             pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1196             pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
1197 
1198             if (chosen != NULL && is_set_recursive(child_rsc, pe_rsc_block, TRUE) == FALSE) {
1199                 pe_rsc_trace(rsc_rh, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
1200                 rhs = g_list_prepend(rhs, chosen);
1201             }
1202         }
1203 
1204         node_list_exclude(rsc_lh->allowed_nodes, rhs, FALSE);
1205         g_list_free(rhs);
1206         return;
1207     }
1208 
1209     gIter = rsc_rh->children;
1210     for (; gIter != NULL; gIter = gIter->next) {
1211         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1212 
1213         child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint,
1214                                            data_set);
1215     }
1216 }
1217 
1218 enum action_tasks
1219 clone_child_action(pe_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
1220 {
1221     enum action_tasks result = no_action;
1222     pe_resource_t *child = (pe_resource_t *) action->rsc->children->data;
1223 
1224     if (pcmk__strcase_any_of(action->task, "notify", "notified", NULL)) {
1225 
1226         /* Find the action we're notifying about instead */
1227 
1228         int stop = 0;
1229         char *key = action->uuid;
1230         int lpc = strlen(key);
1231 
1232         for (; lpc > 0; lpc--) {
1233             if (key[lpc] == '_' && stop == 0) {
1234                 stop = lpc;
1235 
1236             } else if (key[lpc] == '_') {
1237                 char *task_mutable = NULL;
1238 
1239                 lpc++;
1240                 task_mutable = strdup(key + lpc);
1241                 task_mutable[stop - lpc] = 0;
1242 
1243                 crm_trace("Extracted action '%s' from '%s'", task_mutable, key);
1244                 result = get_complex_task(child, task_mutable, TRUE);
1245                 free(task_mutable);
1246                 break;
1247             }
1248         }
1249 
1250     } else {
1251         result = get_complex_task(child, action->task, TRUE);
1252     }
1253     return result;
1254 }
1255 
1256 #define pe__clear_action_summary_flags(flags, action, flag) do {        \
1257         flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,     \
1258                                      "Action summary", action->rsc->id, \
1259                                      flags, flag, #flag);               \
1260     } while (0)
1261 
1262 enum pe_action_flags
1263 summary_action_flags(pe_action_t * action, GList *children, pe_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
1264 {
1265     GList *gIter = NULL;
1266     gboolean any_runnable = FALSE;
1267     gboolean check_runnable = TRUE;
1268     enum action_tasks task = clone_child_action(action);
1269     enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
1270     const char *task_s = task2text(task);
1271 
1272     for (gIter = children; gIter != NULL; gIter = gIter->next) {
1273         pe_action_t *child_action = NULL;
1274         pe_resource_t *child = (pe_resource_t *) gIter->data;
1275 
1276         child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
1277         pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
1278                      node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
1279         if (child_action) {
1280             enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
1281 
1282             if (pcmk_is_set(flags, pe_action_optional)
1283                 && !pcmk_is_set(child_flags, pe_action_optional)) {
1284                 pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
1285                              child_action->uuid);
1286                 pe__clear_action_summary_flags(flags, action, pe_action_optional);
1287                 pe__clear_action_flags(action, pe_action_optional);
1288             }
1289             if (pcmk_is_set(child_flags, pe_action_runnable)) {
1290                 any_runnable = TRUE;
1291             }
1292         }
1293     }
1294 
1295     if (check_runnable && any_runnable == FALSE) {
1296         pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
1297         pe__clear_action_summary_flags(flags, action, pe_action_runnable);
1298         if (node == NULL) {
1299             pe__clear_action_flags(action, pe_action_runnable);
1300         }
1301     }
1302 
1303     return flags;
1304 }
1305 
1306 enum pe_action_flags
1307 clone_action_flags(pe_action_t * action, pe_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
1308 {
1309     return summary_action_flags(action, action->rsc->children, node);
1310 }
1311 
1312 void
1313 clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
     /* [previous][next][first][last][top][bottom][index][help] */
1314 {
1315     GList *gIter = rsc->children;
1316 
1317     pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id);
1318 
1319     native_rsc_location(rsc, constraint);
1320 
1321     for (; gIter != NULL; gIter = gIter->next) {
1322         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1323 
1324         child_rsc->cmds->rsc_location(child_rsc, constraint);
1325     }
1326 }
1327 
1328 void
1329 clone_expand(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
1330 {
1331     GList *gIter = NULL;
1332     clone_variant_data_t *clone_data = NULL;
1333 
1334     get_clone_variant_data(clone_data, rsc);
1335 
1336     gIter = rsc->actions;
1337     for (; gIter != NULL; gIter = gIter->next) {
1338         pe_action_t *op = (pe_action_t *) gIter->data;
1339 
1340         rsc->cmds->action_flags(op, NULL);
1341     }
1342 
1343     if (clone_data->start_notify) {
1344         collect_notification_data(rsc, TRUE, TRUE, clone_data->start_notify);
1345         pcmk__create_notification_keys(rsc, clone_data->start_notify, data_set);
1346         create_notifications(rsc, clone_data->start_notify, data_set);
1347     }
1348 
1349     if (clone_data->stop_notify) {
1350         collect_notification_data(rsc, TRUE, TRUE, clone_data->stop_notify);
1351         pcmk__create_notification_keys(rsc, clone_data->stop_notify, data_set);
1352         create_notifications(rsc, clone_data->stop_notify, data_set);
1353     }
1354 
1355     if (clone_data->promote_notify) {
1356         collect_notification_data(rsc, TRUE, TRUE, clone_data->promote_notify);
1357         pcmk__create_notification_keys(rsc, clone_data->promote_notify, data_set);
1358         create_notifications(rsc, clone_data->promote_notify, data_set);
1359     }
1360 
1361     if (clone_data->demote_notify) {
1362         collect_notification_data(rsc, TRUE, TRUE, clone_data->demote_notify);
1363         pcmk__create_notification_keys(rsc, clone_data->demote_notify, data_set);
1364         create_notifications(rsc, clone_data->demote_notify, data_set);
1365     }
1366 
1367     /* Now that the notifcations have been created we can expand the children */
1368 
1369     gIter = rsc->children;
1370     for (; gIter != NULL; gIter = gIter->next) {
1371         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1372 
1373         child_rsc->cmds->expand(child_rsc, data_set);
1374     }
1375 
1376     native_expand(rsc, data_set);
1377 
1378     /* The notifications are in the graph now, we can destroy the notify_data */
1379     free_notification_data(clone_data->demote_notify);
1380     clone_data->demote_notify = NULL;
1381     free_notification_data(clone_data->stop_notify);
1382     clone_data->stop_notify = NULL;
1383     free_notification_data(clone_data->start_notify);
1384     clone_data->start_notify = NULL;
1385     free_notification_data(clone_data->promote_notify);
1386     clone_data->promote_notify = NULL;
1387 }
1388 
1389 // Check whether a resource or any of its children is known on node
1390 static bool
1391 rsc_known_on(const pe_resource_t *rsc, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1392 {
1393     if (rsc->children) {
1394         for (GList *child_iter = rsc->children; child_iter != NULL;
1395              child_iter = child_iter->next) {
1396 
1397             pe_resource_t *child = (pe_resource_t *) child_iter->data;
1398 
1399             if (rsc_known_on(child, node)) {
1400                 return TRUE;
1401             }
1402         }
1403 
1404     } else if (rsc->known_on) {
1405         GHashTableIter iter;
1406         pe_node_t *known_node = NULL;
1407 
1408         g_hash_table_iter_init(&iter, rsc->known_on);
1409         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &known_node)) {
1410             if (node->details == known_node->details) {
1411                 return TRUE;
1412             }
1413         }
1414     }
1415     return FALSE;
1416 }
1417 
1418 // Look for an instance of clone that is known on node
1419 static pe_resource_t *
1420 find_instance_on(const pe_resource_t *clone, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
1421 {
1422     for (GList *gIter = clone->children; gIter != NULL; gIter = gIter->next) {
1423         pe_resource_t *child = (pe_resource_t *) gIter->data;
1424 
1425         if (rsc_known_on(child, node)) {
1426             return child;
1427         }
1428     }
1429     return NULL;
1430 }
1431 
1432 // For unique clones, probe each instance separately
1433 static gboolean
1434 probe_unique_clone(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete,
     /* [previous][next][first][last][top][bottom][index][help] */
1435                    gboolean force, pe_working_set_t *data_set)
1436 {
1437     gboolean any_created = FALSE;
1438 
1439     for (GList *child_iter = rsc->children; child_iter != NULL;
1440          child_iter = child_iter->next) {
1441 
1442         pe_resource_t *child = (pe_resource_t *) child_iter->data;
1443 
1444         any_created |= child->cmds->create_probe(child, node, complete, force,
1445                                                  data_set);
1446     }
1447     return any_created;
1448 }
1449 
1450 // For anonymous clones, only a single instance needs to be probed
1451 static gboolean
1452 probe_anonymous_clone(pe_resource_t *rsc, pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
1453                       pe_action_t *complete, gboolean force,
1454                       pe_working_set_t *data_set)
1455 {
1456     // First, check if we probed an instance on this node last time
1457     pe_resource_t *child = find_instance_on(rsc, node);
1458 
1459     // Otherwise, check if we plan to start an instance on this node
1460     if (child == NULL) {
1461         for (GList *child_iter = rsc->children; child_iter && !child;
1462              child_iter = child_iter->next) {
1463 
1464             pe_node_t *local_node = NULL;
1465             pe_resource_t *child_rsc = (pe_resource_t *) child_iter->data;
1466 
1467             if (child_rsc) { /* make clang analyzer happy */
1468                 local_node = child_rsc->fns->location(child_rsc, NULL, FALSE);
1469                 if (local_node && (local_node->details == node->details)) {
1470                     child = child_rsc;
1471                 }
1472             }
1473         }
1474     }
1475 
1476     // Otherwise, use the first clone instance
1477     if (child == NULL) {
1478         child = rsc->children->data;
1479     }
1480     CRM_ASSERT(child);
1481     return child->cmds->create_probe(child, node, complete, force, data_set);
1482 }
1483 
1484 gboolean
1485 clone_create_probe(pe_resource_t * rsc, pe_node_t * node, pe_action_t * complete,
     /* [previous][next][first][last][top][bottom][index][help] */
1486                    gboolean force, pe_working_set_t * data_set)
1487 {
1488     gboolean any_created = FALSE;
1489 
1490     CRM_ASSERT(rsc);
1491 
1492     rsc->children = g_list_sort(rsc->children, sort_rsc_id);
1493     if (rsc->children == NULL) {
1494         pe_warn("Clone %s has no children", rsc->id);
1495         return FALSE;
1496     }
1497 
1498     if (rsc->exclusive_discover) {
1499         pe_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1500         if (allowed && allowed->rsc_discover_mode != pe_discover_exclusive) {
1501             /* exclusive discover is enabled and this node is not marked
1502              * as a node this resource should be discovered on
1503              *
1504              * remove the node from allowed_nodes so that the
1505              * notification contains only nodes that we might ever run
1506              * on
1507              */
1508             g_hash_table_remove(rsc->allowed_nodes, node->details->id);
1509 
1510             /* Bit of a shortcut - might as well take it */
1511             return FALSE;
1512         }
1513     }
1514 
1515     if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
1516         any_created = probe_unique_clone(rsc, node, complete, force, data_set);
1517     } else {
1518         any_created = probe_anonymous_clone(rsc, node, complete, force,
1519                                             data_set);
1520     }
1521     return any_created;
1522 }
1523 
1524 void
1525 clone_append_meta(pe_resource_t * rsc, xmlNode * xml)
     /* [previous][next][first][last][top][bottom][index][help] */
1526 {
1527     char *name = NULL;
1528     clone_variant_data_t *clone_data = NULL;
1529 
1530     get_clone_variant_data(clone_data, rsc);
1531 
1532     name = crm_meta_name(XML_RSC_ATTR_UNIQUE);
1533     crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_unique));
1534     free(name);
1535 
1536     name = crm_meta_name(XML_RSC_ATTR_NOTIFY);
1537     crm_xml_add(xml, name, pe__rsc_bool_str(rsc, pe_rsc_notify));
1538     free(name);
1539 
1540     name = crm_meta_name(XML_RSC_ATTR_INCARNATION_MAX);
1541     crm_xml_add_int(xml, name, clone_data->clone_max);
1542     free(name);
1543 
1544     name = crm_meta_name(XML_RSC_ATTR_INCARNATION_NODEMAX);
1545     crm_xml_add_int(xml, name, clone_data->clone_node_max);
1546     free(name);
1547 
1548     if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1549         name = crm_meta_name(XML_RSC_ATTR_PROMOTED_MAX);
1550         crm_xml_add_int(xml, name, clone_data->promoted_max);
1551         free(name);
1552 
1553         name = crm_meta_name(XML_RSC_ATTR_PROMOTED_NODEMAX);
1554         crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1555         free(name);
1556 
1557         /* @COMPAT Maintain backward compatibility with resource agents that
1558          * expect the old names (deprecated since 2.0.0).
1559          */
1560         name = crm_meta_name(PCMK_XE_PROMOTED_MAX_LEGACY);
1561         crm_xml_add_int(xml, name, clone_data->promoted_max);
1562         free(name);
1563 
1564         name = crm_meta_name(PCMK_XE_PROMOTED_NODE_MAX_LEGACY);
1565         crm_xml_add_int(xml, name, clone_data->promoted_node_max);
1566         free(name);
1567     }
1568 }

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