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

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