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. is_child_compatible
  18. find_compatible_child
  19. clone_rsc_colocation_lh
  20. clone_rsc_colocation_rh
  21. clone_child_action
  22. summary_action_flags
  23. clone_action_flags
  24. clone_rsc_location
  25. clone_expand
  26. rsc_known_on
  27. find_instance_on
  28. probe_unique_clone
  29. probe_anonymous_clone
  30. clone_create_probe
  31. clone_append_meta
  32. pcmk__clone_add_utilization
  33. pcmk__clone_shutdown_lock

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

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