This source file includes following definitions.
- order_instance_promotion
 
- order_instance_demotion
 
- check_for_role_change
 
- apply_promoted_locations
 
- node_to_be_promoted_on
 
- cmp_promotable_instance
 
- add_sort_index_to_node_score
 
- apply_coloc_to_primary
 
- set_sort_index_to_node_score
 
- sort_promotable_instances
 
- find_active_anon_instance
 
- anonymous_known_on
 
- is_allowed
 
- promotion_score_applies
 
- promotion_attr_value
 
- promotion_score
 
- pcmk__add_promotion_scores
 
- set_current_role_unpromoted
 
- set_next_role_unpromoted
 
- set_next_role_promoted
 
- show_promotion_score
 
- set_instance_priority
 
- set_instance_role
 
- pcmk__set_instance_roles
 
- create_promotable_instance_actions
 
- reset_instance_priorities
 
- pcmk__create_promotable_actions
 
- pcmk__order_promotable_instances
 
- update_dependent_allowed_nodes
 
- pcmk__update_dependent_with_promotable
 
- pcmk__update_promotable_dependent_priority
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <crm/common/xml.h>
  13 #include <pacemaker-internal.h>
  14 
  15 #include "libpacemaker_private.h"
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 static void
  26 order_instance_promotion(pcmk_resource_t *clone, pcmk_resource_t *child,
     
  27                          pcmk_resource_t *last)
  28 {
  29     
  30     pcmk__order_resource_actions(clone, PCMK_ACTION_PROMOTE,
  31                                  child, PCMK_ACTION_PROMOTE,
  32                                  pcmk__ar_ordered);
  33     pcmk__order_resource_actions(child, PCMK_ACTION_PROMOTE,
  34                                  clone, PCMK_ACTION_PROMOTED,
  35                                  pcmk__ar_ordered);
  36 
  37     
  38     if ((last != NULL) && pe__clone_is_ordered(clone)) {
  39         pcmk__order_resource_actions(last, PCMK_ACTION_PROMOTE,
  40                                      child, PCMK_ACTION_PROMOTE,
  41                                      pcmk__ar_ordered);
  42     }
  43 }
  44 
  45 
  46 
  47 
  48 
  49 
  50 
  51 
  52 
  53 static void
  54 order_instance_demotion(pcmk_resource_t *clone, pcmk_resource_t *child,
     
  55                         pcmk_resource_t *last)
  56 {
  57     
  58     pcmk__order_resource_actions(clone, PCMK_ACTION_DEMOTE, child,
  59                                  PCMK_ACTION_DEMOTE,
  60                                  pcmk__ar_then_implies_first_graphed);
  61     pcmk__order_resource_actions(child, PCMK_ACTION_DEMOTE,
  62                                  clone, PCMK_ACTION_DEMOTED,
  63                                  pcmk__ar_first_implies_then_graphed);
  64 
  65     
  66     if ((last != NULL) && pe__clone_is_ordered(clone)) {
  67         pcmk__order_resource_actions(child, PCMK_ACTION_DEMOTE, last,
  68                                      PCMK_ACTION_DEMOTE, pcmk__ar_ordered);
  69     }
  70 }
  71 
  72 
  73 
  74 
  75 
  76 
  77 
  78 
  79 
  80 static void
  81 check_for_role_change(const pcmk_resource_t *rsc, bool *demoting,
     
  82                       bool *promoting)
  83 {
  84     const GList *iter = NULL;
  85 
  86     
  87     if (rsc->children != NULL) {
  88         for (iter = rsc->children; iter != NULL; iter = iter->next) {
  89             check_for_role_change((const pcmk_resource_t *) iter->data,
  90                                   demoting, promoting);
  91         }
  92         return;
  93     }
  94 
  95     for (iter = rsc->actions; iter != NULL; iter = iter->next) {
  96         const pcmk_action_t *action = (const pcmk_action_t *) iter->data;
  97 
  98         if (*promoting && *demoting) {
  99             return;
 100 
 101         } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
 102             continue;
 103 
 104         } else if (pcmk__str_eq(PCMK_ACTION_DEMOTE, action->task,
 105                                 pcmk__str_none)) {
 106             *demoting = true;
 107 
 108         } else if (pcmk__str_eq(PCMK_ACTION_PROMOTE, action->task,
 109                                 pcmk__str_none)) {
 110             *promoting = true;
 111         }
 112     }
 113 }
 114 
 115 
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 
 126 
 127 static void
 128 apply_promoted_locations(pcmk_resource_t *child,
     
 129                          const GList *location_constraints,
 130                          const pcmk_node_t *chosen)
 131 {
 132     for (const GList *iter = location_constraints; iter; iter = iter->next) {
 133         const pcmk__location_t *location = iter->data;
 134         const pcmk_node_t *constraint_node = NULL;
 135 
 136         if (location->role_filter == pcmk_role_promoted) {
 137             constraint_node = pe_find_node_id(location->nodes,
 138                                               chosen->details->id);
 139         }
 140         if (constraint_node != NULL) {
 141             int new_priority = pcmk__add_scores(child->priority,
 142                                                 constraint_node->weight);
 143 
 144             pcmk__rsc_trace(child,
 145                             "Applying location %s to %s promotion priority on "
 146                             "%s: %s + %s = %s",
 147                             location->id, child->id,
 148                             pcmk__node_name(constraint_node),
 149                             pcmk_readable_score(child->priority),
 150                             pcmk_readable_score(constraint_node->weight),
 151                             pcmk_readable_score(new_priority));
 152             child->priority = new_priority;
 153         }
 154     }
 155 }
 156 
 157 
 158 
 159 
 160 
 161 
 162 
 163 
 164 
 165 static pcmk_node_t *
 166 node_to_be_promoted_on(const pcmk_resource_t *rsc)
     
 167 {
 168     pcmk_node_t *node = NULL;
 169     pcmk_node_t *local_node = NULL;
 170     const pcmk_resource_t *parent = NULL;
 171 
 172     
 173     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 174         pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
 175 
 176         if (node_to_be_promoted_on(child) == NULL) {
 177             pcmk__rsc_trace(rsc,
 178                             "%s can't be promoted because member %s can't",
 179                             rsc->id, child->id);
 180             return NULL;
 181         }
 182     }
 183 
 184     node = rsc->fns->location(rsc, NULL, FALSE);
 185     if (node == NULL) {
 186         pcmk__rsc_trace(rsc, "%s can't be promoted because it won't be active",
 187                         rsc->id);
 188         return NULL;
 189 
 190     } else if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
 191         if (rsc->fns->state(rsc, TRUE) == pcmk_role_promoted) {
 192             crm_notice("Unmanaged instance %s will be left promoted on %s",
 193                        rsc->id, pcmk__node_name(node));
 194         } else {
 195             pcmk__rsc_trace(rsc, "%s can't be promoted because it is unmanaged",
 196                             rsc->id);
 197             return NULL;
 198         }
 199 
 200     } else if (rsc->priority < 0) {
 201         pcmk__rsc_trace(rsc,
 202                         "%s can't be promoted because its promotion priority "
 203                         "%d is negative",
 204                         rsc->id, rsc->priority);
 205         return NULL;
 206 
 207     } else if (!pcmk__node_available(node, false, true)) {
 208         pcmk__rsc_trace(rsc,
 209                         "%s can't be promoted because %s can't run resources",
 210                         rsc->id, pcmk__node_name(node));
 211         return NULL;
 212     }
 213 
 214     parent = pe__const_top_resource(rsc, false);
 215     local_node = g_hash_table_lookup(parent->allowed_nodes, node->details->id);
 216 
 217     if (local_node == NULL) {
 218         
 219 
 220 
 221 
 222         if (pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
 223             pcmk__sched_err("%s can't be promoted because %s is not allowed "
 224                             "on %s (scheduler bug?)",
 225                             rsc->id, parent->id, pcmk__node_name(node));
 226         } 
 227         return NULL;
 228 
 229     } else if ((local_node->count >= pe__clone_promoted_node_max(parent))
 230                && pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
 231         pcmk__rsc_trace(rsc,
 232                         "%s can't be promoted because %s has "
 233                         "maximum promoted instances already",
 234                         rsc->id, pcmk__node_name(node));
 235         return NULL;
 236     }
 237 
 238     return local_node;
 239 }
 240 
 241 
 242 
 243 
 244 
 245 
 246 
 247 
 248 
 249 
 250 
 251 
 252 static gint
 253 cmp_promotable_instance(gconstpointer a, gconstpointer b)
     
 254 {
 255     const pcmk_resource_t *rsc1 = (const pcmk_resource_t *) a;
 256     const pcmk_resource_t *rsc2 = (const pcmk_resource_t *) b;
 257 
 258     enum rsc_role_e role1 = pcmk_role_unknown;
 259     enum rsc_role_e role2 = pcmk_role_unknown;
 260 
 261     CRM_ASSERT((rsc1 != NULL) && (rsc2 != NULL));
 262 
 263     
 264     if (rsc1->sort_index > rsc2->sort_index) {
 265         pcmk__rsc_trace(rsc1,
 266                         "%s has higher promotion priority than %s "
 267                         "(sort index %d > %d)",
 268                         rsc1->id, rsc2->id, rsc1->sort_index, rsc2->sort_index);
 269         return -1;
 270     } else if (rsc1->sort_index < rsc2->sort_index) {
 271         pcmk__rsc_trace(rsc1,
 272                         "%s has lower promotion priority than %s "
 273                         "(sort index %d < %d)",
 274                         rsc1->id, rsc2->id, rsc1->sort_index, rsc2->sort_index);
 275         return 1;
 276     }
 277 
 278     
 279     role1 = rsc1->fns->state(rsc1, TRUE);
 280     role2 = rsc2->fns->state(rsc2, TRUE);
 281     if (role1 > role2) {
 282         pcmk__rsc_trace(rsc1,
 283                         "%s has higher promotion priority than %s "
 284                         "(higher current role)",
 285                         rsc1->id, rsc2->id);
 286         return -1;
 287     } else if (role1 < role2) {
 288         pcmk__rsc_trace(rsc1,
 289                         "%s has lower promotion priority than %s "
 290                         "(lower current role)",
 291                         rsc1->id, rsc2->id);
 292         return 1;
 293     }
 294 
 295     
 296     return pcmk__cmp_instance(a, b);
 297 }
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 
 309 
 310 static void
 311 add_sort_index_to_node_score(gpointer data, gpointer user_data)
     
 312 {
 313     const pcmk_resource_t *child = (const pcmk_resource_t *) data;
 314     pcmk_resource_t *clone = (pcmk_resource_t *) user_data;
 315 
 316     pcmk_node_t *node = NULL;
 317     const pcmk_node_t *chosen = NULL;
 318 
 319     if (child->sort_index < 0) {
 320         pcmk__rsc_trace(clone, "Not adding sort index of %s: negative",
 321                         child->id);
 322         return;
 323     }
 324 
 325     chosen = child->fns->location(child, NULL, FALSE);
 326     if (chosen == NULL) {
 327         pcmk__rsc_trace(clone, "Not adding sort index of %s: inactive",
 328                         child->id);
 329         return;
 330     }
 331 
 332     node = g_hash_table_lookup(clone->allowed_nodes, chosen->details->id);
 333     CRM_ASSERT(node != NULL);
 334 
 335     node->weight = pcmk__add_scores(child->sort_index, node->weight);
 336     pcmk__rsc_trace(clone,
 337                     "Added cumulative priority of %s (%s) to score on %s "
 338                     "(now %s)",
 339                     child->id, pcmk_readable_score(child->sort_index),
 340                     pcmk__node_name(node), pcmk_readable_score(node->weight));
 341 }
 342 
 343 
 344 
 345 
 346 
 347 
 348 
 349 
 350 static void
 351 apply_coloc_to_primary(gpointer data, gpointer user_data)
     
 352 {
 353     pcmk__colocation_t *colocation = data;
 354     pcmk_resource_t *clone = user_data;
 355     pcmk_resource_t *dependent = colocation->dependent;
 356     const float factor = colocation->score / (float) PCMK_SCORE_INFINITY;
 357     const uint32_t flags = pcmk__coloc_select_active
 358                            |pcmk__coloc_select_nonnegative;
 359 
 360     if ((colocation->primary_role != pcmk_role_promoted)
 361          || !pcmk__colocation_has_influence(colocation, NULL)) {
 362         return;
 363     }
 364 
 365     pcmk__rsc_trace(clone, "Applying colocation %s (%s with promoted %s) @%s",
 366                     colocation->id, colocation->dependent->id,
 367                     colocation->primary->id,
 368                     pcmk_readable_score(colocation->score));
 369     dependent->cmds->add_colocated_node_scores(dependent, clone, clone->id,
 370                                                &clone->allowed_nodes,
 371                                                colocation, factor, flags);
 372 }
 373 
 374 
 375 
 376 
 377 
 378 
 379 
 380 
 381 static void
 382 set_sort_index_to_node_score(gpointer data, gpointer user_data)
     
 383 {
 384     pcmk_resource_t *child = (pcmk_resource_t *) data;
 385     const pcmk_resource_t *clone = (const pcmk_resource_t *) user_data;
 386 
 387     pcmk_node_t *chosen = child->fns->location(child, NULL, FALSE);
 388 
 389     if (!pcmk_is_set(child->flags, pcmk_rsc_managed)
 390         && (child->next_role == pcmk_role_promoted)) {
 391         child->sort_index = PCMK_SCORE_INFINITY;
 392         pcmk__rsc_trace(clone,
 393                         "Final sort index for %s is INFINITY "
 394                         "(unmanaged promoted)",
 395                         child->id);
 396 
 397     } else if (chosen == NULL) {
 398         child->sort_index = -PCMK_SCORE_INFINITY;
 399         pcmk__rsc_trace(clone,
 400                         "Final promotion priority for %s is %s "
 401                         "(will not be active)",
 402                         child->id, pcmk_readable_score(-PCMK_SCORE_INFINITY));
 403 
 404     } else if (child->sort_index < 0) {
 405         pcmk__rsc_trace(clone,
 406                         "Final sort index for %s is %d (ignoring node score)",
 407                         child->id, child->sort_index);
 408 
 409     } else {
 410         const pcmk_node_t *node = g_hash_table_lookup(clone->allowed_nodes,
 411                                                       chosen->details->id);
 412 
 413         CRM_ASSERT(node != NULL);
 414         child->sort_index = node->weight;
 415         pcmk__rsc_trace(clone,
 416                         "Adding scores for %s: final sort index for %s is %d",
 417                         clone->id, child->id, child->sort_index);
 418     }
 419 }
 420 
 421 
 422 
 423 
 424 
 425 
 426 
 427 static void
 428 sort_promotable_instances(pcmk_resource_t *clone)
     
 429 {
 430     GList *colocations = NULL;
 431 
 432     if (pe__set_clone_flag(clone, pcmk__clone_promotion_constrained)
 433             == pcmk_rc_already) {
 434         return;
 435     }
 436     pcmk__set_rsc_flags(clone, pcmk_rsc_updating_nodes);
 437 
 438     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
 439         pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
 440 
 441         pcmk__rsc_trace(clone,
 442                         "Adding scores for %s: initial sort index for %s is %d",
 443                         clone->id, child->id, child->sort_index);
 444     }
 445     pe__show_node_scores(true, clone, "Before", clone->allowed_nodes,
 446                          clone->cluster);
 447 
 448     g_list_foreach(clone->children, add_sort_index_to_node_score, clone);
 449 
 450     
 451     colocations = pcmk__with_this_colocations(clone);
 452     g_list_foreach(colocations, apply_coloc_to_primary, clone);
 453     g_list_free(colocations);
 454 
 455     
 456     pcmk__require_promotion_tickets(clone);
 457 
 458     pe__show_node_scores(true, clone, "After", clone->allowed_nodes,
 459                          clone->cluster);
 460 
 461     
 462     g_list_foreach(clone->children, set_sort_index_to_node_score, clone);
 463 
 464     
 465     clone->children = g_list_sort(clone->children, cmp_promotable_instance);
 466     pcmk__clear_rsc_flags(clone, pcmk_rsc_updating_nodes);
 467 }
 468 
 469 
 470 
 471 
 472 
 473 
 474 
 475 
 476 
 477 
 478 
 479 static pcmk_resource_t *
 480 find_active_anon_instance(const pcmk_resource_t *clone, const char *id,
     
 481                           const pcmk_node_t *node)
 482 {
 483     for (GList *iter = clone->children; iter; iter = iter->next) {
 484         pcmk_resource_t *child = iter->data;
 485         pcmk_resource_t *active = NULL;
 486 
 487         
 488         active = clone->fns->find_rsc(child, id, node,
 489                                       pcmk_rsc_match_clone_only
 490                                       |pcmk_rsc_match_current_node);
 491         if (active != NULL) {
 492             return active;
 493         }
 494     }
 495     return NULL;
 496 }
 497 
 498 
 499 
 500 
 501 
 502 
 503 
 504 
 505 
 506 
 507 
 508 static bool
 509 anonymous_known_on(const pcmk_resource_t *clone, const char *id,
     
 510                    const pcmk_node_t *node)
 511 {
 512     for (GList *iter = clone->children; iter; iter = iter->next) {
 513         pcmk_resource_t *child = iter->data;
 514 
 515         
 516 
 517 
 518         child = clone->fns->find_rsc(child, id, NULL,
 519                                      pcmk_rsc_match_clone_only);
 520         CRM_LOG_ASSERT(child != NULL);
 521         if (child != NULL) {
 522             if (g_hash_table_lookup(child->known_on, node->details->id)) {
 523                 return true;
 524             }
 525         }
 526     }
 527     return false;
 528 }
 529 
 530 
 531 
 532 
 533 
 534 
 535 
 536 
 537 
 538 
 539 static bool
 540 is_allowed(const pcmk_resource_t *rsc, const pcmk_node_t *node)
     
 541 {
 542     pcmk_node_t *allowed = g_hash_table_lookup(rsc->allowed_nodes,
 543                                                node->details->id);
 544 
 545     return (allowed != NULL) && (allowed->weight >= 0);
 546 }
 547 
 548 
 549 
 550 
 551 
 552 
 553 
 554 
 555 
 556 
 557 static bool
 558 promotion_score_applies(const pcmk_resource_t *rsc, const pcmk_node_t *node)
     
 559 {
 560     char *id = clone_strip(rsc->id);
 561     const pcmk_resource_t *parent = pe__const_top_resource(rsc, false);
 562     pcmk_resource_t *active = NULL;
 563     const char *reason = "allowed";
 564 
 565     
 566     if (!pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
 567 
 568         
 569         active = find_active_anon_instance(parent, id, node);
 570         if (active == rsc) {
 571             reason = "active";
 572             goto check_allowed;
 573         }
 574 
 575         
 576 
 577 
 578         if ((active == NULL) && anonymous_known_on(parent, id, node)) {
 579             reason = "probed";
 580             goto check_allowed;
 581         }
 582     }
 583 
 584     
 585 
 586 
 587 
 588     if ((rsc->running_on == NULL) && (g_hash_table_size(rsc->known_on) == 0)) {
 589         reason = "none probed";
 590         goto check_allowed;
 591     }
 592 
 593     
 594 
 595 
 596     if ((g_hash_table_lookup(rsc->known_on, node->details->id) != NULL)
 597         || (pe_find_node_id(rsc->running_on, node->details->id) != NULL)) {
 598         reason = "known";
 599     } else {
 600         pcmk__rsc_trace(rsc,
 601                         "Ignoring %s promotion score (for %s) on %s: "
 602                         "not probed",
 603                         rsc->id, id, pcmk__node_name(node));
 604         free(id);
 605         return false;
 606     }
 607 
 608 check_allowed:
 609     if (is_allowed(rsc, node)) {
 610         pcmk__rsc_trace(rsc, "Counting %s promotion score (for %s) on %s: %s",
 611                         rsc->id, id, pcmk__node_name(node), reason);
 612         free(id);
 613         return true;
 614     }
 615 
 616     pcmk__rsc_trace(rsc,
 617                     "Ignoring %s promotion score (for %s) on %s: not allowed",
 618                     rsc->id, id, pcmk__node_name(node));
 619     free(id);
 620     return false;
 621 }
 622 
 623 
 624 
 625 
 626 
 627 
 628 
 629 
 630 
 631 
 632 
 633 static const char *
 634 promotion_attr_value(const pcmk_resource_t *rsc, const pcmk_node_t *node,
     
 635                      const char *name)
 636 {
 637     char *attr_name = NULL;
 638     const char *attr_value = NULL;
 639     const char *target = NULL;
 640     enum pcmk__rsc_node node_type = pcmk__rsc_node_assigned;
 641 
 642     if (pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
 643         
 644         node_type = pcmk__rsc_node_current;
 645     }
 646     target = g_hash_table_lookup(rsc->meta,
 647                                  PCMK_META_CONTAINER_ATTRIBUTE_TARGET);
 648     attr_name = pcmk_promotion_score_name(name);
 649     attr_value = pcmk__node_attr(node, attr_name, target, node_type);
 650     free(attr_name);
 651     return attr_value;
 652 }
 653 
 654 
 655 
 656 
 657 
 658 
 659 
 660 
 661 
 662 
 663 
 664 static int
 665 promotion_score(const pcmk_resource_t *rsc, const pcmk_node_t *node,
     
 666                 bool *is_default)
 667 {
 668     char *name = NULL;
 669     const char *attr_value = NULL;
 670 
 671     if (is_default != NULL) {
 672         *is_default = true;
 673     }
 674 
 675     CRM_CHECK((rsc != NULL) && (node != NULL), return 0);
 676 
 677     
 678 
 679 
 680     if (rsc->children != NULL) {
 681         int score = 0;
 682 
 683         for (const GList *iter = rsc->children;
 684              iter != NULL; iter = iter->next) {
 685 
 686             const pcmk_resource_t *child = (const pcmk_resource_t *) iter->data;
 687             bool child_default = false;
 688             int child_score = promotion_score(child, node, &child_default);
 689 
 690             if (!child_default && (is_default != NULL)) {
 691                 *is_default = false;
 692             }
 693             score += child_score;
 694         }
 695         return score;
 696     }
 697 
 698     if (!promotion_score_applies(rsc, node)) {
 699         return 0;
 700     }
 701 
 702     
 703 
 704 
 705 
 706     name = (rsc->clone_name == NULL)? rsc->id : rsc->clone_name;
 707 
 708     attr_value = promotion_attr_value(rsc, node, name);
 709     if (attr_value != NULL) {
 710         pcmk__rsc_trace(rsc, "Promotion score for %s on %s = %s",
 711                         name, pcmk__node_name(node),
 712                         pcmk__s(attr_value, "(unset)"));
 713     } else if (!pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
 714         
 715 
 716 
 717 
 718         name = clone_strip(rsc->id);
 719         if (strcmp(rsc->id, name) != 0) {
 720             attr_value = promotion_attr_value(rsc, node, name);
 721             pcmk__rsc_trace(rsc, "Promotion score for %s on %s (for %s) = %s",
 722                             name, pcmk__node_name(node), rsc->id,
 723                             pcmk__s(attr_value, "(unset)"));
 724         }
 725         free(name);
 726     }
 727 
 728     if (attr_value == NULL) {
 729         return 0;
 730     }
 731 
 732     if (is_default != NULL) {
 733         *is_default = false;
 734     }
 735     return char2score(attr_value);
 736 }
 737 
 738 
 739 
 740 
 741 
 742 
 743 
 744 void
 745 pcmk__add_promotion_scores(pcmk_resource_t *rsc)
     
 746 {
 747     if (pe__set_clone_flag(rsc,
 748                            pcmk__clone_promotion_added) == pcmk_rc_already) {
 749         return;
 750     }
 751 
 752     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 753         pcmk_resource_t *child_rsc = (pcmk_resource_t *) iter->data;
 754 
 755         GHashTableIter iter;
 756         pcmk_node_t *node = NULL;
 757         int score, new_score;
 758 
 759         g_hash_table_iter_init(&iter, child_rsc->allowed_nodes);
 760         while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
 761             if (!pcmk__node_available(node, false, false)) {
 762                 
 763 
 764 
 765                 continue;
 766             }
 767 
 768             score = promotion_score(child_rsc, node, NULL);
 769             if (score > 0) {
 770                 new_score = pcmk__add_scores(node->weight, score);
 771                 if (new_score != node->weight) { 
 772                     node->weight = new_score;
 773                     pcmk__rsc_trace(rsc,
 774                                     "Added %s promotion priority (%s) to score "
 775                                     "on %s (now %s)",
 776                                     child_rsc->id, pcmk_readable_score(score),
 777                                     pcmk__node_name(node),
 778                                     pcmk_readable_score(new_score));
 779                 }
 780             }
 781 
 782             if (score > child_rsc->priority) {
 783                 pcmk__rsc_trace(rsc,
 784                                 "Updating %s priority to promotion score "
 785                                 "(%d->%d)",
 786                                 child_rsc->id, child_rsc->priority, score);
 787                 child_rsc->priority = score;
 788             }
 789         }
 790     }
 791 }
 792 
 793 
 794 
 795 
 796 
 797 
 798 
 799 
 800 static void
 801 set_current_role_unpromoted(void *data, void *user_data)
     
 802 {
 803     pcmk_resource_t *rsc = (pcmk_resource_t *) data;
 804 
 805     if (rsc->role == pcmk_role_started) {
 806         
 807         rsc->role = pcmk_role_unpromoted;
 808     }
 809     g_list_foreach(rsc->children, set_current_role_unpromoted, NULL);
 810 }
 811 
 812 
 813 
 814 
 815 
 816 
 817 
 818 
 819 static void
 820 set_next_role_unpromoted(void *data, void *user_data)
     
 821 {
 822     pcmk_resource_t *rsc = (pcmk_resource_t *) data;
 823     GList *assigned = NULL;
 824 
 825     rsc->fns->location(rsc, &assigned, FALSE);
 826     if (assigned == NULL) {
 827         pe__set_next_role(rsc, pcmk_role_stopped, "stopped instance");
 828     } else {
 829         pe__set_next_role(rsc, pcmk_role_unpromoted, "unpromoted instance");
 830         g_list_free(assigned);
 831     }
 832     g_list_foreach(rsc->children, set_next_role_unpromoted, NULL);
 833 }
 834 
 835 
 836 
 837 
 838 
 839 
 840 
 841 
 842 static void
 843 set_next_role_promoted(void *data, gpointer user_data)
     
 844 {
 845     pcmk_resource_t *rsc = (pcmk_resource_t *) data;
 846 
 847     if (rsc->next_role == pcmk_role_unknown) {
 848         pe__set_next_role(rsc, pcmk_role_promoted, "promoted instance");
 849     }
 850     g_list_foreach(rsc->children, set_next_role_promoted, NULL);
 851 }
 852 
 853 
 854 
 855 
 856 
 857 
 858 
 859 static void
 860 show_promotion_score(pcmk_resource_t *instance)
     
 861 {
 862     pcmk_node_t *chosen = instance->fns->location(instance, NULL, FALSE);
 863 
 864     if (pcmk_is_set(instance->cluster->flags, pcmk_sched_output_scores)
 865         && !pcmk__is_daemon && (instance->cluster->priv != NULL)) {
 866 
 867         pcmk__output_t *out = instance->cluster->priv;
 868 
 869         out->message(out, "promotion-score", instance, chosen,
 870                      pcmk_readable_score(instance->sort_index));
 871 
 872     } else if (chosen == NULL) {
 873         pcmk__rsc_debug(pe__const_top_resource(instance, false),
 874                         "%s promotion score (inactive): %s (priority=%d)",
 875                         instance->id, pcmk_readable_score(instance->sort_index), instance->priority);
 876 
 877     } else {
 878         pcmk__rsc_debug(pe__const_top_resource(instance, false),
 879                         "%s promotion score on %s: %s (priority=%d)",
 880                         instance->id, pcmk__node_name(chosen),
 881                         pcmk_readable_score(instance->sort_index),
 882                         instance->priority);
 883     }
 884 }
 885 
 886 
 887 
 888 
 889 
 890 
 891 
 892 
 893 static void
 894 set_instance_priority(gpointer data, gpointer user_data)
     
 895 {
 896     pcmk_resource_t *instance = (pcmk_resource_t *) data;
 897     const pcmk_resource_t *clone = (const pcmk_resource_t *) user_data;
 898     const pcmk_node_t *chosen = NULL;
 899     enum rsc_role_e next_role = pcmk_role_unknown;
 900     GList *list = NULL;
 901 
 902     pcmk__rsc_trace(clone, "Assigning priority for %s: %s", instance->id,
 903                     pcmk_role_text(instance->next_role));
 904 
 905     if (instance->fns->state(instance, TRUE) == pcmk_role_started) {
 906         set_current_role_unpromoted(instance, NULL);
 907     }
 908 
 909     
 910     chosen = instance->fns->location(instance, &list, FALSE);
 911     if (pcmk__list_of_multiple(list)) {
 912         pcmk__config_err("Cannot promote non-colocated child %s",
 913                          instance->id);
 914     }
 915     g_list_free(list);
 916     if (chosen == NULL) {
 917         return;
 918     }
 919 
 920     next_role = instance->fns->state(instance, FALSE);
 921     switch (next_role) {
 922         case pcmk_role_started:
 923         case pcmk_role_unknown:
 924             
 925             {
 926                 bool is_default = false;
 927 
 928                 instance->priority = promotion_score(instance, chosen,
 929                                                       &is_default);
 930                 if (is_default) {
 931                     
 932 
 933 
 934 
 935 
 936 
 937                     instance->priority = -1;
 938                 }
 939             }
 940             break;
 941 
 942         case pcmk_role_unpromoted:
 943         case pcmk_role_stopped:
 944             
 945             instance->priority = -PCMK_SCORE_INFINITY;
 946             break;
 947 
 948         case pcmk_role_promoted:
 949             
 950             break;
 951 
 952         default:
 953             CRM_CHECK(FALSE, crm_err("Unknown resource role %d for %s",
 954                                      next_role, instance->id));
 955     }
 956 
 957     
 958     apply_promoted_locations(instance, instance->rsc_location, chosen);
 959     apply_promoted_locations(instance, clone->rsc_location, chosen);
 960 
 961     
 962     list = pcmk__this_with_colocations(instance);
 963     for (GList *iter = list; iter != NULL; iter = iter->next) {
 964         pcmk__colocation_t *cons = (pcmk__colocation_t *) iter->data;
 965 
 966         instance->cmds->apply_coloc_score(instance, cons->primary, cons, true);
 967     }
 968     g_list_free(list);
 969 
 970     instance->sort_index = instance->priority;
 971     if (next_role == pcmk_role_promoted) {
 972         instance->sort_index = PCMK_SCORE_INFINITY;
 973     }
 974     pcmk__rsc_trace(clone, "Assigning %s priority = %d",
 975                     instance->id, instance->priority);
 976 }
 977 
 978 
 979 
 980 
 981 
 982 
 983 
 984 
 985 static void
 986 set_instance_role(gpointer data, gpointer user_data)
     
 987 {
 988     pcmk_resource_t *instance = (pcmk_resource_t *) data;
 989     int *count = (int *) user_data;
 990 
 991     const pcmk_resource_t *clone = pe__const_top_resource(instance, false);
 992     pcmk_node_t *chosen = NULL;
 993 
 994     show_promotion_score(instance);
 995 
 996     if (instance->sort_index < 0) {
 997         pcmk__rsc_trace(clone, "Not supposed to promote instance %s",
 998                         instance->id);
 999 
1000     } else if ((*count < pe__clone_promoted_max(instance))
1001                || !pcmk_is_set(clone->flags, pcmk_rsc_managed)) {
1002         chosen = node_to_be_promoted_on(instance);
1003     }
1004 
1005     if (chosen == NULL) {
1006         set_next_role_unpromoted(instance, NULL);
1007         return;
1008     }
1009 
1010     if ((instance->role < pcmk_role_promoted)
1011         && !pcmk_is_set(instance->cluster->flags, pcmk_sched_quorate)
1012         && (instance->cluster->no_quorum_policy == pcmk_no_quorum_freeze)) {
1013         crm_notice("Clone instance %s cannot be promoted without quorum",
1014                    instance->id);
1015         set_next_role_unpromoted(instance, NULL);
1016         return;
1017     }
1018 
1019     chosen->count++;
1020     pcmk__rsc_info(clone, "Choosing %s (%s) on %s for promotion",
1021                    instance->id, pcmk_role_text(instance->role),
1022                    pcmk__node_name(chosen));
1023     set_next_role_promoted(instance, NULL);
1024     (*count)++;
1025 }
1026 
1027 
1028 
1029 
1030 
1031 
1032 
1033 void
1034 pcmk__set_instance_roles(pcmk_resource_t *rsc)
     
1035 {
1036     int promoted = 0;
1037     GHashTableIter iter;
1038     pcmk_node_t *node = NULL;
1039 
1040     
1041     g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1042     while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1043         node->count = 0;
1044     }
1045 
1046     
1047     g_list_foreach(rsc->children, set_instance_priority, rsc);
1048     sort_promotable_instances(rsc);
1049 
1050     
1051     g_list_foreach(rsc->children, set_instance_role, &promoted);
1052     pcmk__rsc_info(rsc, "%s: Promoted %d instances of a possible %d",
1053                    rsc->id, promoted, pe__clone_promoted_max(rsc));
1054 }
1055 
1056 
1057 
1058 
1059 
1060 
1061 
1062 
1063 
1064 
1065 static void
1066 create_promotable_instance_actions(pcmk_resource_t *clone,
     
1067                                    bool *any_promoting, bool *any_demoting)
1068 {
1069     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
1070         pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1071 
1072         instance->cmds->create_actions(instance);
1073         check_for_role_change(instance, any_demoting, any_promoting);
1074     }
1075 }
1076 
1077 
1078 
1079 
1080 
1081 
1082 
1083 
1084 
1085 
1086 
1087 static void
1088 reset_instance_priorities(pcmk_resource_t *clone)
     
1089 {
1090     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
1091         pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1092 
1093         instance->priority = clone->priority;
1094     }
1095 }
1096 
1097 
1098 
1099 
1100 
1101 
1102 
1103 void
1104 pcmk__create_promotable_actions(pcmk_resource_t *clone)
     
1105 {
1106     bool any_promoting = false;
1107     bool any_demoting = false;
1108 
1109     
1110     create_promotable_instance_actions(clone, &any_promoting, &any_demoting);
1111 
1112     
1113     pe__create_promotable_pseudo_ops(clone, any_promoting, any_demoting);
1114 
1115     
1116     reset_instance_priorities(clone);
1117 }
1118 
1119 
1120 
1121 
1122 
1123 
1124 
1125 void
1126 pcmk__order_promotable_instances(pcmk_resource_t *clone)
     
1127 {
1128     pcmk_resource_t *previous = NULL; 
1129 
1130     pcmk__promotable_restart_ordering(clone);
1131 
1132     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
1133         pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1134 
1135         
1136         pcmk__order_resource_actions(instance, PCMK_ACTION_DEMOTE,
1137                                      instance, PCMK_ACTION_PROMOTE,
1138                                      pcmk__ar_ordered);
1139 
1140         order_instance_promotion(clone, instance, previous);
1141         order_instance_demotion(clone, instance, previous);
1142         previous = instance;
1143     }
1144 }
1145 
1146 
1147 
1148 
1149 
1150 
1151 
1152 
1153 
1154 
1155 static void
1156 update_dependent_allowed_nodes(pcmk_resource_t *dependent,
     
1157                                const pcmk_resource_t *primary,
1158                                const pcmk_node_t *primary_node,
1159                                const pcmk__colocation_t *colocation)
1160 {
1161     GHashTableIter iter;
1162     pcmk_node_t *node = NULL;
1163     const char *primary_value = NULL;
1164     const char *attr = colocation->node_attribute;
1165 
1166     if (colocation->score >= PCMK_SCORE_INFINITY) {
1167         return; 
1168     }
1169 
1170     primary_value = pcmk__colocation_node_attr(primary_node, attr, primary);
1171 
1172     pcmk__rsc_trace(colocation->primary,
1173                     "Applying %s (%s with %s on %s by %s @%d) to %s",
1174                     colocation->id, colocation->dependent->id,
1175                     colocation->primary->id, pcmk__node_name(primary_node),
1176                     attr, colocation->score, dependent->id);
1177 
1178     g_hash_table_iter_init(&iter, dependent->allowed_nodes);
1179     while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1180         const char *dependent_value = pcmk__colocation_node_attr(node, attr,
1181                                                                  dependent);
1182 
1183         if (pcmk__str_eq(primary_value, dependent_value, pcmk__str_casei)) {
1184             node->weight = pcmk__add_scores(node->weight, colocation->score);
1185             pcmk__rsc_trace(colocation->primary,
1186                             "Added %s score (%s) to %s (now %s)",
1187                             colocation->id,
1188                             pcmk_readable_score(colocation->score),
1189                             pcmk__node_name(node),
1190                             pcmk_readable_score(node->weight));
1191         }
1192     }
1193 }
1194 
1195 
1196 
1197 
1198 
1199 
1200 
1201 
1202 void
1203 pcmk__update_dependent_with_promotable(const pcmk_resource_t *primary,
     
1204                                        pcmk_resource_t *dependent,
1205                                        const pcmk__colocation_t *colocation)
1206 {
1207     GList *affected_nodes = NULL;
1208 
1209     
1210 
1211 
1212 
1213     for (GList *iter = primary->children; iter != NULL; iter = iter->next) {
1214         pcmk_resource_t *instance = (pcmk_resource_t *) iter->data;
1215         pcmk_node_t *node = instance->fns->location(instance, NULL, FALSE);
1216 
1217         if (node == NULL) {
1218             continue;
1219         }
1220         if (instance->fns->state(instance, FALSE) == colocation->primary_role) {
1221             update_dependent_allowed_nodes(dependent, primary, node,
1222                                            colocation);
1223             affected_nodes = g_list_prepend(affected_nodes, node);
1224         }
1225     }
1226 
1227     
1228 
1229 
1230 
1231 
1232 
1233 
1234     if ((colocation->score >= PCMK_SCORE_INFINITY)
1235         && ((colocation->dependent_role != pcmk_role_promoted)
1236             || (colocation->primary_role != pcmk_role_promoted))) {
1237 
1238         pcmk__rsc_trace(colocation->primary,
1239                         "Applying %s (mandatory %s with %s) to %s",
1240                         colocation->id, colocation->dependent->id,
1241                         colocation->primary->id, dependent->id);
1242         pcmk__colocation_intersect_nodes(dependent, primary, colocation,
1243                                          affected_nodes, true);
1244     }
1245     g_list_free(affected_nodes);
1246 }
1247 
1248 
1249 
1250 
1251 
1252 
1253 
1254 
1255 
1256 
1257 
1258 int
1259 pcmk__update_promotable_dependent_priority(const pcmk_resource_t *primary,
     
1260                                            pcmk_resource_t *dependent,
1261                                            const pcmk__colocation_t *colocation)
1262 {
1263     pcmk_resource_t *primary_instance = NULL;
1264 
1265     
1266     primary_instance = pcmk__find_compatible_instance(dependent, primary,
1267                                                       colocation->primary_role,
1268                                                       false);
1269 
1270     if (primary_instance != NULL) {
1271         
1272         int new_priority = pcmk__add_scores(dependent->priority,
1273                                             colocation->score);
1274 
1275         pcmk__rsc_trace(colocation->primary,
1276                         "Applying %s (%s with %s) to %s priority "
1277                         "(%s + %s = %s)",
1278                         colocation->id, colocation->dependent->id,
1279                         colocation->primary->id, dependent->id,
1280                         pcmk_readable_score(dependent->priority),
1281                         pcmk_readable_score(colocation->score),
1282                         pcmk_readable_score(new_priority));
1283         dependent->priority = new_priority;
1284         return colocation->score;
1285     }
1286 
1287     if (colocation->score >= PCMK_SCORE_INFINITY) {
1288         
1289         pcmk__rsc_trace(colocation->primary,
1290                         "Applying %s (%s with %s) to %s: can't be promoted",
1291                         colocation->id, colocation->dependent->id,
1292                         colocation->primary->id, dependent->id);
1293         dependent->priority = -PCMK_SCORE_INFINITY;
1294         return -PCMK_SCORE_INFINITY;
1295     }
1296     return 0;
1297 }