root/lib/pacemaker/pcmk_sched_promotable.c

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

DEFINITIONS

This source file includes following definitions.
  1. order_instance_promotion
  2. order_instance_demotion
  3. check_for_role_change
  4. apply_promoted_locations
  5. node_to_be_promoted_on
  6. cmp_promotable_instance
  7. add_sort_index_to_node_weight
  8. apply_coloc_to_dependent
  9. apply_coloc_to_primary
  10. set_sort_index_to_node_weight
  11. sort_promotable_instances
  12. find_active_anon_instance
  13. anonymous_known_on
  14. is_allowed
  15. promotion_score_applies
  16. promotion_attr_value
  17. promotion_score
  18. pcmk__add_promotion_scores
  19. set_current_role_unpromoted
  20. set_next_role_unpromoted
  21. set_next_role_promoted
  22. show_promotion_score
  23. set_instance_priority
  24. set_instance_role
  25. pcmk__set_instance_roles
  26. create_promotable_instance_actions
  27. reset_instance_priorities
  28. pcmk__create_promotable_actions
  29. pcmk__order_promotable_instances
  30. update_dependent_allowed_nodes
  31. pcmk__update_dependent_with_promotable
  32. pcmk__update_promotable_dependent_priority

   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 /*!
  18  * \internal
  19  * \brief Add implicit promotion ordering for a promotable instance
  20  *
  21  * \param[in] clone  Clone resource
  22  * \param[in] child  Instance of \p clone being ordered
  23  * \param[in] last   Previous instance ordered (NULL if \p child is first)
  24  */
  25 static void
  26 order_instance_promotion(pe_resource_t *clone, pe_resource_t *child,
     /* [previous][next][first][last][top][bottom][index][help] */
  27                          pe_resource_t *last)
  28 {
  29     // "Promote clone" -> promote instance -> "clone promoted"
  30     pcmk__order_resource_actions(clone, RSC_PROMOTE, child, RSC_PROMOTE,
  31                                  pe_order_optional);
  32     pcmk__order_resource_actions(child, RSC_PROMOTE, clone, RSC_PROMOTED,
  33                                  pe_order_optional);
  34 
  35     // If clone is ordered, order this instance relative to last
  36     if ((last != NULL) && pe__clone_is_ordered(clone)) {
  37         pcmk__order_resource_actions(last, RSC_PROMOTE, child, RSC_PROMOTE,
  38                                      pe_order_optional);
  39     }
  40 }
  41 
  42 /*!
  43  * \internal
  44  * \brief Add implicit demotion ordering for a promotable instance
  45  *
  46  * \param[in] clone  Clone resource
  47  * \param[in] child  Instance of \p clone being ordered
  48  * \param[in] last   Previous instance ordered (NULL if \p child is first)
  49  */
  50 static void
  51 order_instance_demotion(pe_resource_t *clone, pe_resource_t *child,
     /* [previous][next][first][last][top][bottom][index][help] */
  52                         pe_resource_t *last)
  53 {
  54     // "Demote clone" -> demote instance -> "clone demoted"
  55     pcmk__order_resource_actions(clone, RSC_DEMOTE, child, RSC_DEMOTE,
  56                                  pe_order_implies_first_printed);
  57     pcmk__order_resource_actions(child, RSC_DEMOTE, clone, RSC_DEMOTED,
  58                                  pe_order_implies_then_printed);
  59 
  60     // If clone is ordered, order this instance relative to last
  61     if ((last != NULL) && pe__clone_is_ordered(clone)) {
  62         pcmk__order_resource_actions(child, RSC_DEMOTE, last, RSC_DEMOTE,
  63                                      pe_order_optional);
  64     }
  65 }
  66 
  67 /*!
  68  * \internal
  69  * \brief Check whether an instance will be promoted or demoted
  70  *
  71  * \param[in] rsc        Instance to check
  72  * \param[in] demoting   If \p rsc will be demoted, this will be set to true
  73  * \param[in] promoting  If \p rsc will be promoted, this will be set to true
  74  */
  75 static void
  76 check_for_role_change(pe_resource_t *rsc, bool *demoting, bool *promoting)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78     GList *iter = NULL;
  79 
  80     // If this is a cloned group, check group members recursively
  81     if (rsc->children != NULL) {
  82         for (iter = rsc->children; iter != NULL; iter = iter->next) {
  83             check_for_role_change((pe_resource_t *) iter->data,
  84                                   demoting, promoting);
  85         }
  86         return;
  87     }
  88 
  89     for (iter = rsc->actions; iter != NULL; iter = iter->next) {
  90         pe_action_t *action = (pe_action_t *) iter->data;
  91 
  92         if (*promoting && *demoting) {
  93             return;
  94 
  95         } else if (pcmk_is_set(action->flags, pe_action_optional)) {
  96             continue;
  97 
  98         } else if (pcmk__str_eq(RSC_DEMOTE, action->task, pcmk__str_none)) {
  99             *demoting = true;
 100 
 101         } else if (pcmk__str_eq(RSC_PROMOTE, action->task, pcmk__str_none)) {
 102             *promoting = true;
 103         }
 104     }
 105 }
 106 
 107 /*!
 108  * \internal
 109  * \brief Add promoted-role location constraint scores to an instance's priority
 110  *
 111  * Adjust a promotable clone instance's promotion priority by the scores of any
 112  * location constraints in a list that are both limited to the promoted role and
 113  * for the node where the instance will be placed.
 114  *
 115  * \param[in] child                 Promotable clone instance
 116  * \param[in] location_constraints  List of location constraints to apply
 117  * \param[in] chosen                Node where \p child will be placed
 118  */
 119 static void
 120 apply_promoted_locations(pe_resource_t *child, GList *location_constraints,
     /* [previous][next][first][last][top][bottom][index][help] */
 121                          pe_node_t *chosen)
 122 {
 123     for (GList *iter = location_constraints; iter; iter = iter->next) {
 124         pe__location_t *location = iter->data;
 125         pe_node_t *weighted_node = NULL;
 126 
 127         if (location->role_filter == RSC_ROLE_PROMOTED) {
 128             weighted_node = pe_find_node_id(location->node_list_rh,
 129                                             chosen->details->id);
 130         }
 131         if (weighted_node != NULL) {
 132             int new_priority = pcmk__add_scores(child->priority,
 133                                                 weighted_node->weight);
 134 
 135             pe_rsc_trace(child,
 136                          "Applying location %s to %s promotion priority on %s: "
 137                          "%d + %d = %d",
 138                          location->id, child->id, pe__node_name(weighted_node),
 139                          child->priority, weighted_node->weight, new_priority);
 140             child->priority = new_priority;
 141         }
 142     }
 143 }
 144 
 145 /*!
 146  * \internal
 147  * \brief Get the node that an instance will be promoted on
 148  *
 149  * \param[in] rsc  Promotable clone instance to check
 150  *
 151  * \return Node that \p rsc will be promoted on, or NULL if none
 152  */
 153 static pe_node_t *
 154 node_to_be_promoted_on(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156     pe_node_t *node = NULL;
 157     pe_node_t *local_node = NULL;
 158     pe_resource_t *parent = uber_parent(rsc);
 159 
 160     // If this is a cloned group, bail if any group member can't be promoted
 161     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 162         pe_resource_t *child = (pe_resource_t *) iter->data;
 163 
 164         if (node_to_be_promoted_on(child) == NULL) {
 165             pe_rsc_trace(rsc,
 166                          "%s can't be promoted because member %s can't",
 167                          rsc->id, child->id);
 168             return NULL;
 169         }
 170     }
 171 
 172     node = rsc->fns->location(rsc, NULL, FALSE);
 173     if (node == NULL) {
 174         pe_rsc_trace(rsc, "%s can't be promoted because it won't be active",
 175                      rsc->id);
 176         return NULL;
 177 
 178     } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 179         if (rsc->fns->state(rsc, TRUE) == RSC_ROLE_PROMOTED) {
 180             crm_notice("Unmanaged instance %s will be left promoted on %s",
 181                        rsc->id, pe__node_name(node));
 182         } else {
 183             pe_rsc_trace(rsc, "%s can't be promoted because it is unmanaged",
 184                          rsc->id);
 185             return NULL;
 186         }
 187 
 188     } else if (rsc->priority < 0) {
 189         pe_rsc_trace(rsc,
 190                      "%s can't be promoted because its promotion priority %d "
 191                      "is negative",
 192                      rsc->id, rsc->priority);
 193         return NULL;
 194 
 195     } else if (!pcmk__node_available(node, false, true)) {
 196         pe_rsc_trace(rsc, "%s can't be promoted because %s can't run resources",
 197                      rsc->id, pe__node_name(node));
 198         return NULL;
 199     }
 200 
 201     local_node = pe_hash_table_lookup(parent->allowed_nodes, node->details->id);
 202 
 203     if (local_node == NULL) {
 204         /* It should not be possible for the scheduler to have allocated the
 205          * instance to a node where its parent is not allowed, but it's good to
 206          * have a fail-safe.
 207          */
 208         if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 209             crm_warn("%s can't be promoted because %s is not allowed on %s "
 210                      "(scheduler bug?)",
 211                      rsc->id, parent->id, pe__node_name(node));
 212         } // else the instance is unmanaged and already promoted
 213         return NULL;
 214 
 215     } else if ((local_node->count >= pe__clone_promoted_node_max(parent))
 216                && pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 217         pe_rsc_trace(rsc,
 218                      "%s can't be promoted because %s has "
 219                      "maximum promoted instances already",
 220                      rsc->id, pe__node_name(node));
 221         return NULL;
 222     }
 223 
 224     return local_node;
 225 }
 226 
 227 /*!
 228  * \internal
 229  * \brief Compare two promotable clone instances by promotion priority
 230  *
 231  * \param[in] a  First instance to compare
 232  * \param[in] b  Second instance to compare
 233  *
 234  * \return A negative number if \p a has higher promotion priority,
 235  *         a positive number if \p b has higher promotion priority,
 236  *         or 0 if promotion priorities are equal
 237  */
 238 static gint
 239 cmp_promotable_instance(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241     const pe_resource_t *rsc1 = (const pe_resource_t *) a;
 242     const pe_resource_t *rsc2 = (const pe_resource_t *) b;
 243 
 244     enum rsc_role_e role1 = RSC_ROLE_UNKNOWN;
 245     enum rsc_role_e role2 = RSC_ROLE_UNKNOWN;
 246 
 247     CRM_ASSERT((rsc1 != NULL) && (rsc2 != NULL));
 248 
 249     // Check sort index set by pcmk__set_instance_roles()
 250     if (rsc1->sort_index > rsc2->sort_index) {
 251         pe_rsc_trace(rsc1,
 252                      "%s has higher promotion priority than %s "
 253                      "(sort index %d > %d)",
 254                      rsc1->id, rsc2->id, rsc1->sort_index, rsc2->sort_index);
 255         return -1;
 256     } else if (rsc1->sort_index < rsc2->sort_index) {
 257         pe_rsc_trace(rsc1,
 258                      "%s has lower promotion priority than %s "
 259                      "(sort index %d < %d)",
 260                      rsc1->id, rsc2->id, rsc1->sort_index, rsc2->sort_index);
 261         return 1;
 262     }
 263 
 264     // If those are the same, prefer instance whose current role is higher
 265     role1 = rsc1->fns->state(rsc1, TRUE);
 266     role2 = rsc2->fns->state(rsc2, TRUE);
 267     if (role1 > role2) {
 268         pe_rsc_trace(rsc1,
 269                      "%s has higher promotion priority than %s "
 270                      "(higher current role)",
 271                      rsc1->id, rsc2->id);
 272         return -1;
 273     } else if (role1 < role2) {
 274         pe_rsc_trace(rsc1,
 275                      "%s has lower promotion priority than %s "
 276                      "(lower current role)",
 277                      rsc1->id, rsc2->id);
 278         return 1;
 279     }
 280 
 281     // Finally, do normal clone instance sorting
 282     return pcmk__cmp_instance(a, b);
 283 }
 284 
 285 /*!
 286  * \internal
 287  * \brief Add a promotable clone instance's sort index to its node's weight
 288  *
 289  * Add a promotable clone instance's sort index (which sums its promotion
 290  * preferences and scores of relevant location constraints for the promoted
 291  * role) to the node weight of the instance's allocated node.
 292  *
 293  * \param[in] data       Promotable clone instance
 294  * \param[in] user_data  Clone parent of \p data
 295  */
 296 static void
 297 add_sort_index_to_node_weight(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 298 {
 299     pe_resource_t *child = (pe_resource_t *) data;
 300     pe_resource_t *clone = (pe_resource_t *) user_data;
 301 
 302     pe_node_t *node = NULL;
 303     pe_node_t *chosen = NULL;
 304 
 305     if (child->sort_index < 0) {
 306         pe_rsc_trace(clone, "Not adding sort index of %s: negative", child->id);
 307         return;
 308     }
 309 
 310     chosen = child->fns->location(child, NULL, FALSE);
 311     if (chosen == NULL) {
 312         pe_rsc_trace(clone, "Not adding sort index of %s: inactive", child->id);
 313         return;
 314     }
 315 
 316     node = (pe_node_t *) pe_hash_table_lookup(clone->allowed_nodes,
 317                                               chosen->details->id);
 318     CRM_ASSERT(node != NULL);
 319 
 320     pe_rsc_trace(clone, "Adding sort index %s of %s to weight for %s",
 321                  pcmk_readable_score(child->sort_index), child->id,
 322                  pe__node_name(node));
 323     node->weight = pcmk__add_scores(child->sort_index, node->weight);
 324 }
 325 
 326 /*!
 327  * \internal
 328  * \brief Apply colocation to dependent's node weights if for promoted role
 329  *
 330  * \param[in] data       Colocation constraint to apply
 331  * \param[in] user_data  Promotable clone that is constraint's dependent
 332  */
 333 static void
 334 apply_coloc_to_dependent(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 335 {
 336     pcmk__colocation_t *constraint = (pcmk__colocation_t *) data;
 337     pe_resource_t *clone = (pe_resource_t *) user_data;
 338     pe_resource_t *primary = constraint->primary;
 339     uint32_t flags = pcmk__coloc_select_default;
 340     float factor = constraint->score / (float) INFINITY;
 341 
 342     if (constraint->dependent_role != RSC_ROLE_PROMOTED) {
 343         return;
 344     }
 345     if (constraint->score < INFINITY) {
 346         flags = pcmk__coloc_select_active;
 347     }
 348     pe_rsc_trace(clone, "Applying colocation %s (promoted %s with %s) @%s",
 349                  constraint->id, constraint->dependent->id,
 350                  constraint->primary->id,
 351                  pcmk_readable_score(constraint->score));
 352     pcmk__add_colocated_node_scores(primary, clone->id, &clone->allowed_nodes,
 353                                     constraint->node_attribute, factor, flags);
 354 }
 355 
 356 /*!
 357  * \internal
 358  * \brief Apply colocation to primary's node weights if for promoted role
 359  *
 360  * \param[in] data       Colocation constraint to apply
 361  * \param[in] user_data  Promotable clone that is constraint's primary
 362  */
 363 static void
 364 apply_coloc_to_primary(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366     pcmk__colocation_t *constraint = (pcmk__colocation_t *) data;
 367     pe_resource_t *clone = (pe_resource_t *) user_data;
 368     pe_resource_t *dependent = constraint->dependent;
 369     const float factor = constraint->score / (float) INFINITY;
 370     const uint32_t flags = pcmk__coloc_select_active
 371                            |pcmk__coloc_select_nonnegative;
 372 
 373     if ((constraint->primary_role != RSC_ROLE_PROMOTED)
 374          || !pcmk__colocation_has_influence(constraint, NULL)) {
 375         return;
 376     }
 377 
 378     pe_rsc_trace(clone, "Applying colocation %s (%s with promoted %s) @%s",
 379                  constraint->id, constraint->dependent->id,
 380                  constraint->primary->id,
 381                  pcmk_readable_score(constraint->score));
 382     pcmk__add_colocated_node_scores(dependent, clone->id, &clone->allowed_nodes,
 383                                     constraint->node_attribute, factor, flags);
 384 }
 385 
 386 /*!
 387  * \internal
 388  * \brief Set clone instance's sort index to its node's weight
 389  *
 390  * \param[in] data       Promotable clone instance
 391  * \param[in] user_data  Parent clone of \p data
 392  */
 393 static void
 394 set_sort_index_to_node_weight(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 395 {
 396     pe_resource_t *child = (pe_resource_t *) data;
 397     pe_resource_t *clone = (pe_resource_t *) user_data;
 398 
 399     pe_node_t *chosen = child->fns->location(child, NULL, FALSE);
 400 
 401     if (!pcmk_is_set(child->flags, pe_rsc_managed)
 402         && (child->next_role == RSC_ROLE_PROMOTED)) {
 403         child->sort_index = INFINITY;
 404         pe_rsc_trace(clone,
 405                      "Final sort index for %s is INFINITY (unmanaged promoted)",
 406                      child->id);
 407 
 408     } else if ((chosen == NULL) || (child->sort_index < 0)) {
 409         pe_rsc_trace(clone,
 410                      "Final sort index for %s is %d (ignoring node weight)",
 411                      child->id, child->sort_index);
 412 
 413     } else {
 414         pe_node_t *node = NULL;
 415 
 416         node = (pe_node_t *) pe_hash_table_lookup(clone->allowed_nodes,
 417                                                   chosen->details->id);
 418         CRM_ASSERT(node != NULL);
 419 
 420         child->sort_index = node->weight;
 421         pe_rsc_trace(clone,
 422                      "Merging weights for %s: final sort index for %s is %d",
 423                      clone->id, child->id, child->sort_index);
 424     }
 425 }
 426 
 427 /*!
 428  * \internal
 429  * \brief Sort a promotable clone's instances by descending promotion priority
 430  *
 431  * \param[in] clone  Promotable clone to sort
 432  */
 433 static void
 434 sort_promotable_instances(pe_resource_t *clone)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436     if (pe__set_clone_flag(clone, pe__clone_promotion_constrained)
 437             == pcmk_rc_already) {
 438         return;
 439     }
 440     pe__set_resource_flags(clone, pe_rsc_merging);
 441 
 442     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
 443         pe_resource_t *child = (pe_resource_t *) iter->data;
 444 
 445         pe_rsc_trace(clone,
 446                      "Merging weights for %s: initial sort index for %s is %d",
 447                      clone->id, child->id, child->sort_index);
 448     }
 449     pe__show_node_weights(true, clone, "Before", clone->allowed_nodes,
 450                           clone->cluster);
 451 
 452     g_list_foreach(clone->children, add_sort_index_to_node_weight, clone);
 453     g_list_foreach(clone->rsc_cons, apply_coloc_to_dependent, clone);
 454     g_list_foreach(clone->rsc_cons_lhs, apply_coloc_to_primary, clone);
 455 
 456     // Ban resource from all nodes if it needs a ticket but doesn't have it
 457     pcmk__require_promotion_tickets(clone);
 458 
 459     pe__show_node_weights(true, clone, "After", clone->allowed_nodes,
 460                           clone->cluster);
 461 
 462     // Reset sort indexes to final node weights
 463     g_list_foreach(clone->children, set_sort_index_to_node_weight, clone);
 464 
 465     // Finally, sort instances in descending order of promotion priority
 466     clone->children = g_list_sort(clone->children, cmp_promotable_instance);
 467     pe__clear_resource_flags(clone, pe_rsc_merging);
 468 }
 469 
 470 /*!
 471  * \internal
 472  * \brief Find the active instance (if any) of an anonymous clone on a node
 473  *
 474  * \param[in] clone  Anonymous clone to check
 475  * \param[in] id     Instance ID (without instance number) to check
 476  * \param[in] node   Node to check
 477  *
 478  * \return
 479  */
 480 static pe_resource_t *
 481 find_active_anon_instance(pe_resource_t *clone, const char *id,
     /* [previous][next][first][last][top][bottom][index][help] */
 482                           const pe_node_t *node)
 483 {
 484     for (GList *iter = clone->children; iter; iter = iter->next) {
 485         pe_resource_t *child = iter->data;
 486         pe_resource_t *active = NULL;
 487 
 488         // Use ->find_rsc() in case this is a cloned group
 489         active = clone->fns->find_rsc(child, id, node,
 490                                       pe_find_clone|pe_find_current);
 491         if (active != NULL) {
 492             return active;
 493         }
 494     }
 495     return NULL;
 496 }
 497 
 498 /*
 499  * \brief Check whether an anonymous clone instance is known on a node
 500  *
 501  * \param[in] clone  Anonymous clone to check
 502  * \param[in] id     Instance ID (without instance number) to check
 503  * \param[in] node   Node to check
 504  *
 505  * \return true if \p id instance of \p clone is known on \p node,
 506  *         otherwise false
 507  */
 508 static bool
 509 anonymous_known_on(const pe_resource_t *clone, const char *id,
     /* [previous][next][first][last][top][bottom][index][help] */
 510                    const pe_node_t *node)
 511 {
 512     for (GList *iter = clone->children; iter; iter = iter->next) {
 513         pe_resource_t *child = iter->data;
 514 
 515         /* Use ->find_rsc() because this might be a cloned group, and knowing
 516          * that other members of the group are known here implies nothing.
 517          */
 518         child = clone->fns->find_rsc(child, id, NULL, pe_find_clone);
 519         CRM_LOG_ASSERT(child != NULL);
 520         if (child != NULL) {
 521             if (g_hash_table_lookup(child->known_on, node->details->id)) {
 522                 return true;
 523             }
 524         }
 525     }
 526     return false;
 527 }
 528 
 529 /*!
 530  * \internal
 531  * \brief Check whether a node is allowed to run a resource
 532  *
 533  * \param[in] rsc   Resource to check
 534  * \param[in] node  Node to check
 535  *
 536  * \return true if \p node is allowed to run \p rsc, otherwise false
 537  */
 538 static bool
 539 is_allowed(const pe_resource_t *rsc, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 540 {
 541     pe_node_t *allowed = pe_hash_table_lookup(rsc->allowed_nodes,
 542                                               node->details->id);
 543 
 544     return (allowed != NULL) && (allowed->weight >= 0);
 545 }
 546 
 547 /*!
 548  * \brief Check whether a clone instance's promotion score should be considered
 549  *
 550  * \param[in] rsc   Promotable clone instance to check
 551  * \param[in] node  Node where score would be applied
 552  *
 553  * \return true if \p rsc's promotion score should be considered on \p node,
 554  *         otherwise false
 555  */
 556 static bool
 557 promotion_score_applies(pe_resource_t *rsc, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 558 {
 559     char *id = clone_strip(rsc->id);
 560     pe_resource_t *parent = uber_parent(rsc);
 561     pe_resource_t *active = NULL;
 562     const char *reason = "allowed";
 563 
 564     // Some checks apply only to anonymous clone instances
 565     if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
 566 
 567         // If instance is active on the node, its score definitely applies
 568         active = find_active_anon_instance(parent, id, node);
 569         if (active == rsc) {
 570             reason = "active";
 571             goto check_allowed;
 572         }
 573 
 574         /* If *no* instance is active on this node, this instance's score will
 575          * count if it has been probed on this node.
 576          */
 577         if ((active == NULL) && anonymous_known_on(parent, id, node)) {
 578             reason = "probed";
 579             goto check_allowed;
 580         }
 581     }
 582 
 583     /* If this clone's status is unknown on *all* nodes (e.g. cluster startup),
 584      * take all instances' scores into account, to make sure we use any
 585      * permanent promotion scores.
 586      */
 587     if ((rsc->running_on == NULL) && (g_hash_table_size(rsc->known_on) == 0)) {
 588         reason = "none probed";
 589         goto check_allowed;
 590     }
 591 
 592     /* Otherwise, we've probed and/or started the resource *somewhere*, so
 593      * consider promotion scores on nodes where we know the status.
 594      */
 595     if ((pe_hash_table_lookup(rsc->known_on, node->details->id) != NULL)
 596         || (pe_find_node_id(rsc->running_on, node->details->id) != NULL)) {
 597         reason = "known";
 598     } else {
 599         pe_rsc_trace(rsc,
 600                      "Ignoring %s promotion score (for %s) on %s: not probed",
 601                      rsc->id, id, pe__node_name(node));
 602         free(id);
 603         return false;
 604     }
 605 
 606 check_allowed:
 607     if (is_allowed(rsc, node)) {
 608         pe_rsc_trace(rsc, "Counting %s promotion score (for %s) on %s: %s",
 609                      rsc->id, id, pe__node_name(node), reason);
 610         free(id);
 611         return true;
 612     }
 613 
 614     pe_rsc_trace(rsc, "Ignoring %s promotion score (for %s) on %s: not allowed",
 615                  rsc->id, id, pe__node_name(node));
 616     free(id);
 617     return false;
 618 }
 619 
 620 /*!
 621  * \internal
 622  * \brief Get the value of a promotion score node attribute
 623  *
 624  * \param[in] rsc   Promotable clone instance to get promotion score for
 625  * \param[in] node  Node to get promotion score for
 626  * \param[in] name  Resource name to use in promotion score attribute name
 627  *
 628  * \return Value of promotion score node attribute for \p rsc on \p node
 629  */
 630 static const char *
 631 promotion_attr_value(pe_resource_t *rsc, const pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
 632                      const char *name)
 633 {
 634     char *attr_name = NULL;
 635     const char *attr_value = NULL;
 636 
 637     CRM_CHECK((rsc != NULL) && (node != NULL) && (name != NULL), return NULL);
 638 
 639     attr_name = pcmk_promotion_score_name(name);
 640     attr_value = pe_node_attribute_calculated(node, attr_name, rsc);
 641     free(attr_name);
 642     return attr_value;
 643 }
 644 
 645 /*!
 646  * \internal
 647  * \brief Get the promotion score for a clone instance on a node
 648  *
 649  * \param[in]  rsc         Promotable clone instance to get score for
 650  * \param[in]  node        Node to get score for
 651  * \param[out] is_default  If non-NULL, will be set true if no score available
 652  *
 653  * \return Promotion score for \p rsc on \p node (or 0 if none)
 654  */
 655 static int
 656 promotion_score(pe_resource_t *rsc, const pe_node_t *node, bool *is_default)
     /* [previous][next][first][last][top][bottom][index][help] */
 657 {
 658     char *name = NULL;
 659     const char *attr_value = NULL;
 660 
 661     if (is_default != NULL) {
 662         *is_default = true;
 663     }
 664 
 665     CRM_CHECK((rsc != NULL) && (node != NULL), return 0);
 666 
 667     /* If this is an instance of a cloned group, the promotion score is the sum
 668      * of all members' promotion scores.
 669      */
 670     if (rsc->children != NULL) {
 671         int score = 0;
 672 
 673         for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 674             pe_resource_t *child = (pe_resource_t *) iter->data;
 675             bool child_default = false;
 676             int child_score = promotion_score(child, node, &child_default);
 677 
 678             if (!child_default && (is_default != NULL)) {
 679                 *is_default = false;
 680             }
 681             score += child_score;
 682         }
 683         return score;
 684     }
 685 
 686     if (!promotion_score_applies(rsc, node)) {
 687         return 0;
 688     }
 689 
 690     /* For the promotion score attribute name, use the name the resource is
 691      * known as in resource history, since that's what crm_attribute --promotion
 692      * would have used.
 693      */
 694     name = (rsc->clone_name == NULL)? rsc->id : rsc->clone_name;
 695 
 696     attr_value = promotion_attr_value(rsc, node, name);
 697     if (attr_value != NULL) {
 698         pe_rsc_trace(rsc, "Promotion score for %s on %s = %s",
 699                      name, pe__node_name(node), pcmk__s(attr_value, "(unset)"));
 700     } else if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
 701         /* If we don't have any resource history yet, we won't have clone_name.
 702          * In that case, for anonymous clones, try the resource name without
 703          * any instance number.
 704          */
 705         name = clone_strip(rsc->id);
 706         if (strcmp(rsc->id, name) != 0) {
 707             attr_value = promotion_attr_value(rsc, node, name);
 708             pe_rsc_trace(rsc, "Promotion score for %s on %s (for %s) = %s",
 709                          name, pe__node_name(node), rsc->id,
 710                          pcmk__s(attr_value, "(unset)"));
 711         }
 712         free(name);
 713     }
 714 
 715     if (attr_value == NULL) {
 716         return 0;
 717     }
 718 
 719     if (is_default != NULL) {
 720         *is_default = false;
 721     }
 722     return char2score(attr_value);
 723 }
 724 
 725 /*!
 726  * \internal
 727  * \brief Include promotion scores in instances' node weights and priorities
 728  *
 729  * \param[in] rsc  Promotable clone resource to update
 730  */
 731 void
 732 pcmk__add_promotion_scores(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 733 {
 734     if (pe__set_clone_flag(rsc, pe__clone_promotion_added) == pcmk_rc_already) {
 735         return;
 736     }
 737 
 738     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 739         pe_resource_t *child_rsc = (pe_resource_t *) iter->data;
 740 
 741         GHashTableIter iter;
 742         pe_node_t *node = NULL;
 743         int score, new_score;
 744 
 745         g_hash_table_iter_init(&iter, child_rsc->allowed_nodes);
 746         while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
 747             if (!pcmk__node_available(node, false, false)) {
 748                 /* This node will never be promoted, so don't apply the
 749                  * promotion score, as that may lead to clone shuffling.
 750                  */
 751                 continue;
 752             }
 753 
 754             score = promotion_score(child_rsc, node, NULL);
 755             if (score > 0) {
 756                 new_score = pcmk__add_scores(node->weight, score);
 757                 if (new_score != node->weight) {
 758                     pe_rsc_trace(rsc,
 759                                  "Adding promotion score to preference "
 760                                  "for %s on %s (%d->%d)",
 761                                  child_rsc->id, pe__node_name(node),
 762                                  node->weight, new_score);
 763                     node->weight = new_score;
 764                 }
 765             }
 766 
 767             if (score > child_rsc->priority) {
 768                 pe_rsc_trace(rsc,
 769                              "Updating %s priority to promotion score (%d->%d)",
 770                              child_rsc->id, child_rsc->priority, score);
 771                 child_rsc->priority = score;
 772             }
 773         }
 774     }
 775 }
 776 
 777 /*!
 778  * \internal
 779  * \brief If a resource's current role is started, change it to unpromoted
 780  *
 781  * \param[in] data       Resource to update
 782  * \param[in] user_data  Ignored
 783  */
 784 static void
 785 set_current_role_unpromoted(void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 786 {
 787     pe_resource_t *rsc = (pe_resource_t *) data;
 788 
 789     if (rsc->role == RSC_ROLE_STARTED) {
 790         // Promotable clones should use unpromoted role instead of started
 791         rsc->role = RSC_ROLE_UNPROMOTED;
 792     }
 793     g_list_foreach(rsc->children, set_current_role_unpromoted, NULL);
 794 }
 795 
 796 /*!
 797  * \internal
 798  * \brief Set a resource's next role to unpromoted (or stopped if unassigned)
 799  *
 800  * \param[in] data       Resource to update
 801  * \param[in] user_data  Ignored
 802  */
 803 static void
 804 set_next_role_unpromoted(void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 805 {
 806     pe_resource_t *rsc = (pe_resource_t *) data;
 807     GList *assigned = NULL;
 808 
 809     rsc->fns->location(rsc, &assigned, FALSE);
 810     if (assigned == NULL) {
 811         pe__set_next_role(rsc, RSC_ROLE_STOPPED, "stopped instance");
 812     } else {
 813         pe__set_next_role(rsc, RSC_ROLE_UNPROMOTED, "unpromoted instance");
 814         g_list_free(assigned);
 815     }
 816     g_list_foreach(rsc->children, set_next_role_unpromoted, NULL);
 817 }
 818 
 819 /*!
 820  * \internal
 821  * \brief Set a resource's next role to promoted if not already set
 822  *
 823  * \param[in] data       Resource to update
 824  * \param[in] user_data  Ignored
 825  */
 826 static void
 827 set_next_role_promoted(void *data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 828 {
 829     pe_resource_t *rsc = (pe_resource_t *) data;
 830 
 831     if (rsc->next_role == RSC_ROLE_UNKNOWN) {
 832         pe__set_next_role(rsc, RSC_ROLE_PROMOTED, "promoted instance");
 833     }
 834     g_list_foreach(rsc->children, set_next_role_promoted, NULL);
 835 }
 836 
 837 /*!
 838  * \internal
 839  * \brief Show instance's promotion score on node where it will be active
 840  *
 841  * \param[in] instance  Promotable clone instance to show
 842  */
 843 static void
 844 show_promotion_score(pe_resource_t *instance)
     /* [previous][next][first][last][top][bottom][index][help] */
 845 {
 846     pe_node_t *chosen = instance->fns->location(instance, NULL, FALSE);
 847 
 848     if (pcmk_is_set(instance->cluster->flags, pe_flag_show_scores)
 849         && !pcmk__is_daemon && (instance->cluster->priv != NULL)) {
 850 
 851         pcmk__output_t *out = instance->cluster->priv;
 852 
 853         out->message(out, "promotion-score", instance, chosen,
 854                      pcmk_readable_score(instance->sort_index));
 855     } else {
 856         pe_rsc_debug(uber_parent(instance),
 857                      "%s promotion score on %s: sort=%s priority=%s",
 858                      instance->id,
 859                      ((chosen == NULL)? "none" : pe__node_name(chosen)),
 860                      pcmk_readable_score(instance->sort_index),
 861                      pcmk_readable_score(instance->priority));
 862     }
 863 }
 864 
 865 /*!
 866  * \internal
 867  * \brief Set a clone instance's promotion priority
 868  *
 869  * \param[in] data       Promotable clone instance to update
 870  * \param[in] user_data  Instance's parent clone
 871  */
 872 static void
 873 set_instance_priority(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 874 {
 875     pe_resource_t *instance = (pe_resource_t *) data;
 876     pe_resource_t *clone = (pe_resource_t *) user_data;
 877     pe_node_t *chosen = NULL;
 878     enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
 879     GList *list = NULL;
 880 
 881     pe_rsc_trace(clone, "Assigning priority for %s: %s", instance->id,
 882                  role2text(instance->next_role));
 883 
 884     if (instance->fns->state(instance, TRUE) == RSC_ROLE_STARTED) {
 885         set_current_role_unpromoted(instance, NULL);
 886     }
 887 
 888     // Only an instance that will be active can be promoted
 889     chosen = instance->fns->location(instance, &list, FALSE);
 890     if (pcmk__list_of_multiple(list)) {
 891         pcmk__config_err("Cannot promote non-colocated child %s",
 892                          instance->id);
 893     }
 894     g_list_free(list);
 895     if (chosen == NULL) {
 896         return;
 897     }
 898 
 899     next_role = instance->fns->state(instance, FALSE);
 900     switch (next_role) {
 901         case RSC_ROLE_STARTED:
 902         case RSC_ROLE_UNKNOWN:
 903             // Set instance priority to its promotion score (or -1 if none)
 904             {
 905                 bool is_default = false;
 906 
 907                 instance->priority = promotion_score(instance, chosen,
 908                                                       &is_default);
 909                 if (is_default) {
 910                     /*
 911                      * Default to -1 if no value is set. This allows
 912                      * instances eligible for promotion to be specified
 913                      * based solely on rsc_location constraints, but
 914                      * prevents any instance from being promoted if neither
 915                      * a constraint nor a promotion score is present
 916                      */
 917                     instance->priority = -1;
 918                 }
 919             }
 920             break;
 921 
 922         case RSC_ROLE_UNPROMOTED:
 923         case RSC_ROLE_STOPPED:
 924             // Instance can't be promoted
 925             instance->priority = -INFINITY;
 926             break;
 927 
 928         case RSC_ROLE_PROMOTED:
 929             // Nothing needed (re-creating actions after scheduling fencing)
 930             break;
 931 
 932         default:
 933             CRM_CHECK(FALSE, crm_err("Unknown resource role %d for %s",
 934                                      next_role, instance->id));
 935     }
 936 
 937     // Add relevant location constraint scores for promoted role
 938     apply_promoted_locations(instance, instance->rsc_location, chosen);
 939     apply_promoted_locations(instance, clone->rsc_location, chosen);
 940 
 941     // Apply relevant colocations with promoted role
 942     for (GList *iter = instance->rsc_cons; iter != NULL; iter = iter->next) {
 943         pcmk__colocation_t *cons = (pcmk__colocation_t *) iter->data;
 944 
 945         instance->cmds->apply_coloc_score(instance, cons->primary, cons, true);
 946     }
 947 
 948     instance->sort_index = instance->priority;
 949     if (next_role == RSC_ROLE_PROMOTED) {
 950         instance->sort_index = INFINITY;
 951     }
 952     pe_rsc_trace(clone, "Assigning %s priority = %d",
 953                  instance->id, instance->priority);
 954 }
 955 
 956 /*!
 957  * \internal
 958  * \brief Set a promotable clone instance's role
 959  *
 960  * \param[in] data       Promotable clone instance to update
 961  * \param[in] user_data  Pointer to count of instances chosen for promotion
 962  */
 963 static void
 964 set_instance_role(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 965 {
 966     pe_resource_t *instance = (pe_resource_t *) data;
 967     int *count = (int *) user_data;
 968 
 969     pe_resource_t *clone = uber_parent(instance);
 970     pe_node_t *chosen = NULL;
 971 
 972     show_promotion_score(instance);
 973 
 974     if (instance->sort_index < 0) {
 975         pe_rsc_trace(clone, "Not supposed to promote instance %s",
 976                      instance->id);
 977 
 978     } else if ((*count < pe__clone_promoted_max(instance))
 979                || !pcmk_is_set(clone->flags, pe_rsc_managed)) {
 980         chosen = node_to_be_promoted_on(instance);
 981     }
 982 
 983     if (chosen == NULL) {
 984         set_next_role_unpromoted(instance, NULL);
 985         return;
 986     }
 987 
 988     if ((instance->role < RSC_ROLE_PROMOTED)
 989         && !pcmk_is_set(instance->cluster->flags, pe_flag_have_quorum)
 990         && (instance->cluster->no_quorum_policy == no_quorum_freeze)) {
 991         crm_notice("Clone instance %s cannot be promoted without quorum",
 992                    instance->id);
 993         set_next_role_unpromoted(instance, NULL);
 994         return;
 995     }
 996 
 997     chosen->count++;
 998     pe_rsc_info(clone, "Choosing %s (%s) on %s for promotion",
 999                 instance->id, role2text(instance->role),
1000                 pe__node_name(chosen));
1001     set_next_role_promoted(instance, NULL);
1002     (*count)++;
1003 }
1004 
1005 /*!
1006  * \internal
1007  * \brief Set roles for all instances of a promotable clone
1008  *
1009  * \param[in] clone  Promotable clone resource to update
1010  */
1011 void
1012 pcmk__set_instance_roles(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
1013 {
1014     int promoted = 0;
1015     GHashTableIter iter;
1016     pe_node_t *node = NULL;
1017 
1018     // Repurpose count to track the number of promoted instances allocated
1019     g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1020     while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
1021         node->count = 0;
1022     }
1023 
1024     // Set instances' promotion priorities and sort by highest priority first
1025     g_list_foreach(rsc->children, set_instance_priority, rsc);
1026     sort_promotable_instances(rsc);
1027 
1028     // Choose the first N eligible instances to be promoted
1029     g_list_foreach(rsc->children, set_instance_role, &promoted);
1030     pe_rsc_info(rsc, "%s: Promoted %d instances of a possible %d",
1031                 rsc->id, promoted, pe__clone_promoted_max(rsc));
1032 }
1033 
1034 /*!
1035  *
1036  * \internal
1037  * \brief Create actions for promotable clone instances
1038  *
1039  * \param[in]  clone          Promotable clone to create actions for
1040  * \param[out] any_promoting  Will be set true if any instance is promoting
1041  * \param[out] any_demoting   Will be set true if any instance is demoting
1042  */
1043 static void
1044 create_promotable_instance_actions(pe_resource_t *clone,
     /* [previous][next][first][last][top][bottom][index][help] */
1045                                    bool *any_promoting, bool *any_demoting)
1046 {
1047     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
1048         pe_resource_t *instance = (pe_resource_t *) iter->data;
1049 
1050         instance->cmds->create_actions(instance);
1051         check_for_role_change(instance, any_demoting, any_promoting);
1052     }
1053 }
1054 
1055 /*!
1056  * \internal
1057  * \brief Reset each promotable instance's resource priority
1058  *
1059  * Reset the priority of each instance of a promotable clone to the clone's
1060  * priority (after promotion actions are scheduled, when instance priorities
1061  * were repurposed as promotion scores).
1062  *
1063  * \param[in] clone  Promotable clone to reset
1064  */
1065 static void
1066 reset_instance_priorities(pe_resource_t *clone)
     /* [previous][next][first][last][top][bottom][index][help] */
1067 {
1068     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
1069         pe_resource_t *instance = (pe_resource_t *) iter->data;
1070 
1071         instance->priority = clone->priority;
1072     }
1073 }
1074 
1075 /*!
1076  * \internal
1077  * \brief Create actions specific to promotable clones
1078  *
1079  * \param[in] clone  Promotable clone to create actions for
1080  */
1081 void
1082 pcmk__create_promotable_actions(pe_resource_t *clone)
     /* [previous][next][first][last][top][bottom][index][help] */
1083 {
1084     bool any_promoting = false;
1085     bool any_demoting = false;
1086 
1087     // Create actions for each clone instance individually
1088     create_promotable_instance_actions(clone, &any_promoting, &any_demoting);
1089 
1090     // Create pseudo-actions for clone as a whole
1091     pe__create_promotable_pseudo_ops(clone, any_promoting, any_demoting);
1092 
1093     // Undo our temporary repurposing of resource priority for instances
1094     reset_instance_priorities(clone);
1095 }
1096 
1097 /*!
1098  * \internal
1099  * \brief Create internal orderings for a promotable clone's instances
1100  *
1101  * \param[in] clone  Promotable clone instance to order
1102  */
1103 void
1104 pcmk__order_promotable_instances(pe_resource_t *clone)
     /* [previous][next][first][last][top][bottom][index][help] */
1105 {
1106     pe_resource_t *previous = NULL; // Needed for ordered clones
1107 
1108     pcmk__promotable_restart_ordering(clone);
1109 
1110     for (GList *iter = clone->children; iter != NULL; iter = iter->next) {
1111         pe_resource_t *instance = (pe_resource_t *) iter->data;
1112 
1113         // Demote before promote
1114         pcmk__order_resource_actions(instance, RSC_DEMOTE,
1115                                      instance, RSC_PROMOTE,
1116                                      pe_order_optional);
1117 
1118         order_instance_promotion(clone, instance, previous);
1119         order_instance_demotion(clone, instance, previous);
1120         previous = instance;
1121     }
1122 }
1123 
1124 /*!
1125  * \internal
1126  * \brief Update dependent's allowed nodes for colocation with promotable
1127  *
1128  * \param[in,out] dependent     Dependent resource to update
1129  * \param[in]     primary_node  Node where an instance of the primary will be
1130  * \param[in]     colocation    Colocation constraint to apply
1131  */
1132 static void
1133 update_dependent_allowed_nodes(pe_resource_t *dependent,
     /* [previous][next][first][last][top][bottom][index][help] */
1134                                const pe_node_t *primary_node,
1135                                const pcmk__colocation_t *colocation)
1136 {
1137     GHashTableIter iter;
1138     pe_node_t *node = NULL;
1139     const char *primary_value = NULL;
1140     const char *attr = NULL;
1141 
1142     if (colocation->score >= INFINITY) {
1143         return; // Colocation is mandatory, so allowed node scores don't matter
1144     }
1145 
1146     // Get value of primary's colocation node attribute
1147     attr = colocation->node_attribute;
1148     if (attr == NULL) {
1149         attr = CRM_ATTR_UNAME;
1150     }
1151     primary_value = pe_node_attribute_raw(primary_node, attr);
1152 
1153     pe_rsc_trace(colocation->primary,
1154                  "Applying %s (%s with %s on %s by %s @%d) to %s",
1155                  colocation->id, colocation->dependent->id,
1156                  colocation->primary->id, pe__node_name(primary_node), attr,
1157                  colocation->score, dependent->id);
1158 
1159     g_hash_table_iter_init(&iter, dependent->allowed_nodes);
1160     while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1161         const char *dependent_value = pe_node_attribute_raw(node, attr);
1162 
1163         if (pcmk__str_eq(primary_value, dependent_value, pcmk__str_casei)) {
1164             pe_rsc_trace(colocation->primary, "%s: %d + %d",
1165                          pe__node_name(node), node->weight, colocation->score);
1166             node->weight = pcmk__add_scores(node->weight, colocation->score);
1167         }
1168     }
1169 }
1170 
1171 /*!
1172  * \brief Update dependent for a colocation with a promotable clone
1173  *
1174  * \param[in]     primary     Primary resource in the colocation
1175  * \param[in,out] dependent   Dependent resource in the colocation
1176  * \param[in]     colocation  Colocation constraint to apply
1177  */
1178 void
1179 pcmk__update_dependent_with_promotable(const pe_resource_t *primary,
     /* [previous][next][first][last][top][bottom][index][help] */
1180                                        pe_resource_t *dependent,
1181                                        const pcmk__colocation_t *colocation)
1182 {
1183     GList *affected_nodes = NULL;
1184 
1185     /* Build a list of all nodes where an instance of the primary will be, and
1186      * (for optional colocations) update the dependent's allowed node scores for
1187      * each one.
1188      */
1189     for (GList *iter = primary->children; iter != NULL; iter = iter->next) {
1190         pe_resource_t *instance = (pe_resource_t *) iter->data;
1191         pe_node_t *node = instance->fns->location(instance, NULL, FALSE);
1192 
1193         if (node == NULL) {
1194             continue;
1195         }
1196         if (instance->fns->state(instance, FALSE) == colocation->primary_role) {
1197             update_dependent_allowed_nodes(dependent, node, colocation);
1198             affected_nodes = g_list_prepend(affected_nodes, node);
1199         }
1200     }
1201 
1202     /* For mandatory colocations, add the primary's node weight to the
1203      * dependent's node weight for each affected node, and ban the dependent
1204      * from all other nodes.
1205      *
1206      * However, skip this for promoted-with-promoted colocations, otherwise
1207      * inactive dependent instances can't start (in the unpromoted role).
1208      */
1209     if ((colocation->score >= INFINITY)
1210         && ((colocation->dependent_role != RSC_ROLE_PROMOTED)
1211             || (colocation->primary_role != RSC_ROLE_PROMOTED))) {
1212 
1213         pe_rsc_trace(colocation->primary,
1214                      "Applying %s (mandatory %s with %s) to %s",
1215                      colocation->id, colocation->dependent->id,
1216                      colocation->primary->id, dependent->id);
1217         node_list_exclude(dependent->allowed_nodes, affected_nodes,
1218                           TRUE);
1219     }
1220     g_list_free(affected_nodes);
1221 }
1222 
1223 /*!
1224  * \internal
1225  * \brief Update dependent priority for colocation with promotable
1226  *
1227  * \param[in]     primary     Primary resource in the colocation
1228  * \param[in,out] dependent   Dependent resource in the colocation
1229  * \param[in]     colocation  Colocation constraint to apply
1230  */
1231 void
1232 pcmk__update_promotable_dependent_priority(const pe_resource_t *primary,
     /* [previous][next][first][last][top][bottom][index][help] */
1233                                            pe_resource_t *dependent,
1234                                            const pcmk__colocation_t *colocation)
1235 {
1236     pe_resource_t *primary_instance = NULL;
1237 
1238     // Look for a primary instance where dependent will be
1239     primary_instance = find_compatible_child(dependent, primary,
1240                                              colocation->primary_role, FALSE);
1241 
1242     if (primary_instance != NULL) {
1243         // Add primary instance's priority to dependent's
1244         int new_priority = pcmk__add_scores(dependent->priority,
1245                                             colocation->score);
1246 
1247         pe_rsc_trace(colocation->primary,
1248                      "Applying %s (%s with %s) to %s priority (%s + %s = %s)",
1249                      colocation->id, colocation->dependent->id,
1250                      colocation->primary->id, dependent->id,
1251                      pcmk_readable_score(dependent->priority),
1252                      pcmk_readable_score(colocation->score),
1253                      pcmk_readable_score(new_priority));
1254         dependent->priority = new_priority;
1255 
1256     } else if (colocation->score >= INFINITY) {
1257         // Mandatory colocation, but primary won't be here
1258         pe_rsc_trace(colocation->primary,
1259                      "Applying %s (%s with %s) to %s: can't be promoted",
1260                      colocation->id, colocation->dependent->id,
1261                      colocation->primary->id, dependent->id);
1262         dependent->priority = -INFINITY;
1263     }
1264 }

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