root/lib/pacemaker/pcmk_sched_promotable.c

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

DEFINITIONS

This source file includes following definitions.
  1. child_promoting_constraints
  2. child_demoting_constraints
  3. check_promotable_actions
  4. apply_promoted_location
  5. guest_location
  6. node_to_be_promoted_on
  7. sort_promotable_instance
  8. promotion_order
  9. filter_anonymous_instance
  10. lookup_promotion_score
  11. promotion_score
  12. pcmk__add_promotion_scores
  13. set_role_unpromoted
  14. set_role_promoted
  15. pcmk__set_instance_roles
  16. create_promotable_actions
  17. promote_demote_constraints
  18. promotable_constraints
  19. node_hash_update_one
  20. promotable_colocation_rh

   1 /*
   2  * Copyright 2004-2021 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <crm/msg_xml.h>
  13 #include <pacemaker-internal.h>
  14 
  15 #define VARIANT_CLONE 1
  16 #include <lib/pengine/variant.h>
  17 
  18 extern gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
  19 
  20 extern bool pcmk__is_daemon;
  21 
  22 static void
  23 child_promoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
     /* [previous][next][first][last][top][bottom][index][help] */
  24                             pe_resource_t * rsc, pe_resource_t * child, pe_resource_t * last,
  25                             pe_working_set_t * data_set)
  26 {
  27     if (child == NULL) {
  28         if (clone_data->ordered && last != NULL) {
  29             pe_rsc_trace(rsc, "Ordered version (last node)");
  30             /* last child promote before promoted started */
  31             new_rsc_order(last, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set);
  32         }
  33         return;
  34     }
  35 
  36     /* child promote before global promoted */
  37     new_rsc_order(child, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set);
  38 
  39     /* global promote before child promote */
  40     new_rsc_order(rsc, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set);
  41 
  42     if (clone_data->ordered) {
  43         pe_rsc_trace(rsc, "Ordered version");
  44         if (last == NULL) {
  45             /* global promote before first child promote */
  46             last = rsc;
  47 
  48         }
  49         /* else: child/child relative promote */
  50         order_start_start(last, child, type);
  51         new_rsc_order(last, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set);
  52 
  53     } else {
  54         pe_rsc_trace(rsc, "Un-ordered version");
  55     }
  56 }
  57 
  58 static void
  59 child_demoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
     /* [previous][next][first][last][top][bottom][index][help] */
  60                            pe_resource_t * rsc, pe_resource_t * child, pe_resource_t * last,
  61                            pe_working_set_t * data_set)
  62 {
  63     if (child == NULL) {
  64         if (clone_data->ordered && last != NULL) {
  65             pe_rsc_trace(rsc, "Ordered version (last node)");
  66             /* global demote before first child demote */
  67             new_rsc_order(rsc, RSC_DEMOTE, last, RSC_DEMOTE, pe_order_optional, data_set);
  68         }
  69         return;
  70     }
  71 
  72     /* child demote before global demoted */
  73     new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, pe_order_implies_then_printed, data_set);
  74 
  75     /* global demote before child demote */
  76     new_rsc_order(rsc, RSC_DEMOTE, child, RSC_DEMOTE, pe_order_implies_first_printed, data_set);
  77 
  78     if (clone_data->ordered && last != NULL) {
  79         pe_rsc_trace(rsc, "Ordered version");
  80 
  81         /* child/child relative demote */
  82         new_rsc_order(child, RSC_DEMOTE, last, RSC_DEMOTE, type, data_set);
  83 
  84     } else if (clone_data->ordered) {
  85         pe_rsc_trace(rsc, "Ordered version (1st node)");
  86         /* first child stop before global stopped */
  87         new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, type, data_set);
  88 
  89     } else {
  90         pe_rsc_trace(rsc, "Un-ordered version");
  91     }
  92 }
  93 
  94 static void
  95 check_promotable_actions(pe_resource_t *rsc, gboolean *demoting,
     /* [previous][next][first][last][top][bottom][index][help] */
  96                          gboolean *promoting)
  97 {
  98     GList *gIter = NULL;
  99 
 100     if (rsc->children) {
 101         gIter = rsc->children;
 102         for (; gIter != NULL; gIter = gIter->next) {
 103             pe_resource_t *child = (pe_resource_t *) gIter->data;
 104 
 105             check_promotable_actions(child, demoting, promoting);
 106         }
 107         return;
 108     }
 109 
 110     CRM_ASSERT(demoting != NULL);
 111     CRM_ASSERT(promoting != NULL);
 112 
 113     gIter = rsc->actions;
 114     for (; gIter != NULL; gIter = gIter->next) {
 115         pe_action_t *action = (pe_action_t *) gIter->data;
 116 
 117         if (*promoting && *demoting) {
 118             return;
 119 
 120         } else if (pcmk_is_set(action->flags, pe_action_optional)) {
 121             continue;
 122 
 123         } else if (pcmk__str_eq(RSC_DEMOTE, action->task, pcmk__str_casei)) {
 124             *demoting = TRUE;
 125 
 126         } else if (pcmk__str_eq(RSC_PROMOTE, action->task, pcmk__str_casei)) {
 127             *promoting = TRUE;
 128         }
 129     }
 130 }
 131 
 132 static void
 133 apply_promoted_location(pe_resource_t *child, GList *location_constraints,
     /* [previous][next][first][last][top][bottom][index][help] */
 134                         pe_node_t *chosen)
 135 {
 136     CRM_CHECK(child && chosen, return);
 137     for (GList *gIter = location_constraints; gIter; gIter = gIter->next) {
 138         pe_node_t *cons_node = NULL;
 139         pe__location_t *cons = gIter->data;
 140 
 141         if (cons->role_filter == RSC_ROLE_PROMOTED) {
 142             pe_rsc_trace(child, "Applying %s to %s", cons->id, child->id);
 143             cons_node = pe_find_node_id(cons->node_list_rh, chosen->details->id);
 144         }
 145         if (cons_node != NULL) {
 146             int new_priority = pe__add_scores(child->priority,
 147                                               cons_node->weight);
 148 
 149             pe_rsc_trace(child, "\t%s[%s]: %d -> %d (%d)",
 150                          child->id, cons_node->details->uname, child->priority,
 151                          new_priority, cons_node->weight);
 152             child->priority = new_priority;
 153         }
 154     }
 155 }
 156 
 157 static pe_node_t *
 158 guest_location(pe_node_t *guest_node)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160     pe_resource_t *guest = guest_node->details->remote_rsc->container;
 161 
 162     return guest->fns->location(guest, NULL, FALSE);
 163 }
 164 
 165 static pe_node_t *
 166 node_to_be_promoted_on(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168     pe_node_t *node = NULL;
 169     pe_node_t *local_node = NULL;
 170     pe_resource_t *parent = uber_parent(rsc);
 171     clone_variant_data_t *clone_data = NULL;
 172 
 173 #if 0
 174     enum rsc_role_e role = RSC_ROLE_UNKNOWN;
 175 
 176     role = rsc->fns->state(rsc, FALSE);
 177     crm_info("%s role: %s", rsc->id, role2text(role));
 178 #endif
 179 
 180     if (rsc->children) {
 181         GList *gIter = rsc->children;
 182 
 183         for (; gIter != NULL; gIter = gIter->next) {
 184             pe_resource_t *child = (pe_resource_t *) gIter->data;
 185 
 186             if (node_to_be_promoted_on(child) == NULL) {
 187                 pe_rsc_trace(rsc, "Child %s of %s can't be promoted", child->id, rsc->id);
 188                 return NULL;
 189             }
 190         }
 191     }
 192 
 193     node = rsc->fns->location(rsc, NULL, FALSE);
 194     if (node == NULL) {
 195         pe_rsc_trace(rsc, "%s cannot be promoted: not allocated", rsc->id);
 196         return NULL;
 197 
 198     } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 199         if (rsc->fns->state(rsc, TRUE) == RSC_ROLE_PROMOTED) {
 200             crm_notice("Forcing unmanaged instance %s to remain promoted on %s",
 201                        rsc->id, node->details->uname);
 202 
 203         } else {
 204             return NULL;
 205         }
 206 
 207     } else if (rsc->priority < 0) {
 208         pe_rsc_trace(rsc, "%s cannot be promoted: preference: %d",
 209                      rsc->id, rsc->priority);
 210         return NULL;
 211 
 212     } else if (can_run_resources(node) == FALSE) {
 213         crm_trace("Node can't run any resources: %s", node->details->uname);
 214         return NULL;
 215 
 216     /* @TODO It's possible this check should be done in can_run_resources()
 217      * instead. We should investigate all its callers to figure out whether that
 218      * would be a good idea.
 219      */
 220     } else if (pe__is_guest_node(node) && (guest_location(node) == NULL)) {
 221         pe_rsc_trace(rsc, "%s cannot be promoted: guest %s not allocated",
 222                      rsc->id, node->details->remote_rsc->container->id);
 223         return NULL;
 224     }
 225 
 226     get_clone_variant_data(clone_data, parent);
 227     local_node = pe_hash_table_lookup(parent->allowed_nodes, node->details->id);
 228 
 229     if (local_node == NULL) {
 230         crm_err("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
 231         return NULL;
 232 
 233     } else if ((local_node->count < clone_data->promoted_node_max)
 234                || !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 235         return local_node;
 236 
 237     } else {
 238         pe_rsc_trace(rsc, "%s cannot be promoted on %s: node full",
 239                      rsc->id, node->details->uname);
 240     }
 241 
 242     return NULL;
 243 }
 244 
 245 static gint
 246 sort_promotable_instance(gconstpointer a, gconstpointer b, gpointer data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248     int rc;
 249     enum rsc_role_e role1 = RSC_ROLE_UNKNOWN;
 250     enum rsc_role_e role2 = RSC_ROLE_UNKNOWN;
 251 
 252     const pe_resource_t *resource1 = (const pe_resource_t *)a;
 253     const pe_resource_t *resource2 = (const pe_resource_t *)b;
 254 
 255     CRM_ASSERT(resource1 != NULL);
 256     CRM_ASSERT(resource2 != NULL);
 257 
 258     role1 = resource1->fns->state(resource1, TRUE);
 259     role2 = resource2->fns->state(resource2, TRUE);
 260 
 261     rc = sort_rsc_index(a, b);
 262     if (rc != 0) {
 263         crm_trace("%s %c %s (index)", resource1->id, rc < 0 ? '<' : '>', resource2->id);
 264         return rc;
 265     }
 266 
 267     if (role1 > role2) {
 268         crm_trace("%s %c %s (role)", resource1->id, '<', resource2->id);
 269         return -1;
 270 
 271     } else if (role1 < role2) {
 272         crm_trace("%s %c %s (role)", resource1->id, '>', resource2->id);
 273         return 1;
 274     }
 275 
 276     return sort_clone_instance(a, b, data_set);
 277 }
 278 
 279 static void
 280 promotion_order(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282     GList *gIter = NULL;
 283     pe_node_t *node = NULL;
 284     pe_node_t *chosen = NULL;
 285     clone_variant_data_t *clone_data = NULL;
 286     char score[33];
 287     size_t len = sizeof(score);
 288 
 289     get_clone_variant_data(clone_data, rsc);
 290 
 291     if (clone_data->added_promoted_constraints) {
 292         return;
 293     }
 294     clone_data->added_promoted_constraints = true;
 295     pe_rsc_trace(rsc, "Merging weights for %s", rsc->id);
 296     pe__set_resource_flags(rsc, pe_rsc_merging);
 297 
 298     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 299         pe_resource_t *child = (pe_resource_t *) gIter->data;
 300 
 301         pe_rsc_trace(rsc, "Sort index: %s = %d", child->id, child->sort_index);
 302     }
 303     pe__show_node_weights(true, rsc, "Before", rsc->allowed_nodes, data_set);
 304 
 305     gIter = rsc->children;
 306     for (; gIter != NULL; gIter = gIter->next) {
 307         pe_resource_t *child = (pe_resource_t *) gIter->data;
 308 
 309         chosen = child->fns->location(child, NULL, FALSE);
 310         if (chosen == NULL || child->sort_index < 0) {
 311             pe_rsc_trace(rsc, "Skipping %s", child->id);
 312             continue;
 313         }
 314 
 315         node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
 316         CRM_ASSERT(node != NULL);
 317         // Add promotion preferences and rsc_location scores when role=Promoted
 318         score2char_stack(child->sort_index, score, len);
 319         pe_rsc_trace(rsc, "Adding %s to %s from %s", score,
 320                      node->details->uname, child->id);
 321         node->weight = pe__add_scores(child->sort_index, node->weight);
 322     }
 323 
 324     pe__show_node_weights(true, rsc, "Middle", rsc->allowed_nodes, data_set);
 325 
 326     gIter = rsc->rsc_cons;
 327     for (; gIter != NULL; gIter = gIter->next) {
 328         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 329 
 330         /* (Re-)add location preferences of resources that a promoted instance
 331          * should/must be colocated with.
 332          */
 333         if (constraint->role_lh == RSC_ROLE_PROMOTED) {
 334             enum pe_weights flags = constraint->score == INFINITY ? 0 : pe_weights_rollback;
 335 
 336             pe_rsc_trace(rsc, "RHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id,
 337                          constraint->score);
 338             rsc->allowed_nodes =
 339                 constraint->rsc_rh->cmds->merge_weights(constraint->rsc_rh, rsc->id,
 340                                                         rsc->allowed_nodes,
 341                                                         constraint->node_attribute,
 342                                                         (float)constraint->score / INFINITY, flags);
 343         }
 344     }
 345 
 346     gIter = rsc->rsc_cons_lhs;
 347     for (; gIter != NULL; gIter = gIter->next) {
 348         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 349 
 350         if (!pcmk__colocation_has_influence(constraint, NULL)) {
 351             continue;
 352         }
 353 
 354         /* (Re-)add location preferences of resources that wish to be colocated
 355          * with a promoted instance.
 356          */
 357         if (constraint->role_rh == RSC_ROLE_PROMOTED) {
 358             pe_rsc_trace(rsc, "LHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id,
 359                          constraint->score);
 360             rsc->allowed_nodes =
 361                 constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id,
 362                                                         rsc->allowed_nodes,
 363                                                         constraint->node_attribute,
 364                                                         (float)constraint->score / INFINITY,
 365                                                         (pe_weights_rollback |
 366                                                          pe_weights_positive));
 367         }
 368     }
 369 
 370     gIter = rsc->rsc_tickets;
 371     for (; gIter != NULL; gIter = gIter->next) {
 372         rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) gIter->data;
 373 
 374         if ((rsc_ticket->role_lh == RSC_ROLE_PROMOTED)
 375             && (rsc_ticket->ticket->granted == FALSE || rsc_ticket->ticket->standby)) {
 376             resource_location(rsc, NULL, -INFINITY, "__stateful_without_ticket__", data_set);
 377         }
 378     }
 379 
 380     pe__show_node_weights(true, rsc, "After", rsc->allowed_nodes, data_set);
 381 
 382     /* write them back and sort */
 383 
 384     gIter = rsc->children;
 385     for (; gIter != NULL; gIter = gIter->next) {
 386         pe_resource_t *child = (pe_resource_t *) gIter->data;
 387 
 388         chosen = child->fns->location(child, NULL, FALSE);
 389         if (!pcmk_is_set(child->flags, pe_rsc_managed)
 390             && (child->next_role == RSC_ROLE_PROMOTED)) {
 391             child->sort_index = INFINITY;
 392 
 393         } else if (chosen == NULL || child->sort_index < 0) {
 394             pe_rsc_trace(rsc, "%s: %d", child->id, child->sort_index);
 395 
 396         } else {
 397             node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
 398             CRM_ASSERT(node != NULL);
 399 
 400             child->sort_index = node->weight;
 401         }
 402         pe_rsc_trace(rsc, "Set sort index: %s = %d", child->id, child->sort_index);
 403     }
 404 
 405     rsc->children = g_list_sort_with_data(rsc->children,
 406                                           sort_promotable_instance, data_set);
 407     pe__clear_resource_flags(rsc, pe_rsc_merging);
 408 }
 409 
 410 static gboolean
 411 filter_anonymous_instance(pe_resource_t *rsc, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 412 {
 413     GList *rIter = NULL;
 414     char *key = clone_strip(rsc->id);
 415     pe_resource_t *parent = uber_parent(rsc);
 416 
 417     for (rIter = parent->children; rIter; rIter = rIter->next) {
 418         /* If there is an active instance on the node, only it receives the
 419          * promotion score. Use ->find_rsc() in case this is a cloned group.
 420          */
 421         pe_resource_t *child = rIter->data;
 422         pe_resource_t *active = parent->fns->find_rsc(child, key, node, pe_find_clone|pe_find_current);
 423 
 424         if(rsc == active) {
 425             pe_rsc_trace(rsc, "Found %s for %s active on %s: done", active->id, key, node->details->uname);
 426             free(key);
 427             return TRUE;
 428         } else if(active) {
 429             pe_rsc_trace(rsc, "Found %s for %s on %s: not %s", active->id, key, node->details->uname, rsc->id);
 430             free(key);
 431             return FALSE;
 432         } else {
 433             pe_rsc_trace(rsc, "%s on %s: not active", key, node->details->uname);
 434         }
 435     }
 436 
 437     for (rIter = parent->children; rIter; rIter = rIter->next) {
 438         pe_resource_t *child = rIter->data;
 439 
 440         /*
 441          * We know it's not running, but any score will still count if
 442          * the instance has been probed on $node
 443          *
 444          * Again use ->find_rsc() because we might be a cloned group
 445          * and knowing that other members of the group are known here
 446          * implies nothing
 447          */
 448         rsc = parent->fns->find_rsc(child, key, NULL, pe_find_clone);
 449         CRM_LOG_ASSERT(rsc);
 450         if(rsc) {
 451             pe_rsc_trace(rsc, "Checking %s for %s on %s", rsc->id, key, node->details->uname);
 452             if (g_hash_table_lookup(rsc->known_on, node->details->id)) {
 453                 free(key);
 454                 return TRUE;
 455             }
 456         }
 457     }
 458     free(key);
 459     return FALSE;
 460 }
 461 
 462 static const char *
 463 lookup_promotion_score(pe_resource_t *rsc, const pe_node_t *node, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 464 {
 465     const char *attr_value = NULL;
 466 
 467     if (node && name) {
 468         char *attr_name = pcmk_promotion_score_name(name);
 469 
 470         attr_value = pe_node_attribute_calculated(node, attr_name, rsc);
 471         free(attr_name);
 472     }
 473     return attr_value;
 474 }
 475 
 476 static int
 477 promotion_score(pe_resource_t *rsc, const pe_node_t *node, int not_set_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 478 {
 479     char *name = rsc->id;
 480     const char *attr_value = NULL;
 481     int score = not_set_value;
 482     pe_node_t *match = NULL;
 483 
 484     CRM_CHECK(node != NULL, return not_set_value);
 485 
 486     if (rsc->children) {
 487         GList *gIter = rsc->children;
 488 
 489         for (; gIter != NULL; gIter = gIter->next) {
 490             pe_resource_t *child = (pe_resource_t *) gIter->data;
 491             int c_score = promotion_score(child, node, not_set_value);
 492 
 493             if (score == not_set_value) {
 494                 score = c_score;
 495             } else {
 496                 score += c_score;
 497             }
 498         }
 499         return score;
 500     }
 501 
 502     if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
 503         && filter_anonymous_instance(rsc, node)) {
 504 
 505         pe_rsc_trace(rsc, "Anonymous clone %s is allowed on %s", rsc->id, node->details->uname);
 506 
 507     } else if (rsc->running_on || g_hash_table_size(rsc->known_on)) {
 508         /* If we've probed and/or started the resource anywhere, consider
 509          * promotion scores only from nodes where we know the status. However,
 510          * if the status of all nodes is unknown (e.g. cluster startup),
 511          * skip this code, to make sure we take into account any permanent
 512          * promotion scores set previously.
 513          */
 514         pe_node_t *known = pe_hash_table_lookup(rsc->known_on, node->details->id);
 515 
 516         match = pe_find_node_id(rsc->running_on, node->details->id);
 517         if ((match == NULL) && (known == NULL)) {
 518             pe_rsc_trace(rsc, "skipping %s (aka. %s) promotion score on %s because inactive",
 519                          rsc->id, rsc->clone_name, node->details->uname);
 520             return score;
 521         }
 522     }
 523 
 524     match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
 525     if (match == NULL) {
 526         return score;
 527 
 528     } else if (match->weight < 0) {
 529         pe_rsc_trace(rsc, "%s on %s has score: %d - ignoring",
 530                      rsc->id, match->details->uname, match->weight);
 531         return score;
 532     }
 533 
 534     if (rsc->clone_name) {
 535         /* Use the name the lrm knows this resource as,
 536          * since that's what crm_attribute --promotion would have used
 537          */
 538         name = rsc->clone_name;
 539     }
 540 
 541     attr_value = lookup_promotion_score(rsc, node, name);
 542     pe_rsc_trace(rsc, "promotion score for %s on %s = %s",
 543                  name, node->details->uname, crm_str(attr_value));
 544 
 545     if ((attr_value == NULL) && !pcmk_is_set(rsc->flags, pe_rsc_unique)) {
 546         /* If we don't have any LRM history yet, we won't have clone_name -- in
 547          * that case, for anonymous clones, try the resource name without any
 548          * instance number.
 549          */
 550         name = clone_strip(rsc->id);
 551         if (strcmp(rsc->id, name)) {
 552             attr_value = lookup_promotion_score(rsc, node, name);
 553             pe_rsc_trace(rsc, "stripped promotion score for %s on %s = %s",
 554                          name, node->details->uname, crm_str(attr_value));
 555         }
 556         free(name);
 557     }
 558 
 559     if (attr_value != NULL) {
 560         score = char2score(attr_value);
 561     }
 562 
 563     return score;
 564 }
 565 
 566 void
 567 pcmk__add_promotion_scores(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 568 {
 569     int score, new_score;
 570     GList *gIter = rsc->children;
 571     clone_variant_data_t *clone_data = NULL;
 572 
 573     get_clone_variant_data(clone_data, rsc);
 574 
 575     if (clone_data->added_promotion_scores) {
 576         /* Make sure we only do this once */
 577         return;
 578     }
 579 
 580     clone_data->added_promotion_scores = true;
 581 
 582     for (; gIter != NULL; gIter = gIter->next) {
 583         GHashTableIter iter;
 584         pe_node_t *node = NULL;
 585         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 586 
 587         g_hash_table_iter_init(&iter, child_rsc->allowed_nodes);
 588         while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 589             if (can_run_resources(node) == FALSE) {
 590                 /* This node will never be promoted, so don't apply the
 591                  * promotion score, as that may lead to clone shuffling.
 592                  */
 593                 continue;
 594             }
 595 
 596             score = promotion_score(child_rsc, node, 0);
 597             if (score > 0) {
 598                 new_score = pe__add_scores(node->weight, score);
 599                 if (new_score != node->weight) {
 600                     pe_rsc_trace(rsc, "\t%s: Updating preference for %s (%d->%d)",
 601                                  child_rsc->id, node->details->uname, node->weight, new_score);
 602                     node->weight = new_score;
 603                 }
 604             }
 605 
 606             new_score = QB_MAX(child_rsc->priority, score);
 607             if (new_score != child_rsc->priority) {
 608                 pe_rsc_trace(rsc, "\t%s: Updating priority (%d->%d)",
 609                              child_rsc->id, child_rsc->priority, new_score);
 610                 child_rsc->priority = new_score;
 611             }
 612         }
 613     }
 614 }
 615 
 616 static void
 617 set_role_unpromoted(pe_resource_t *rsc, bool current)
     /* [previous][next][first][last][top][bottom][index][help] */
 618 {
 619     GList *gIter = rsc->children;
 620 
 621     if (current) {
 622         if (rsc->role == RSC_ROLE_STARTED) {
 623             rsc->role = RSC_ROLE_UNPROMOTED;
 624         }
 625 
 626     } else {
 627         GList *allocated = NULL;
 628 
 629         rsc->fns->location(rsc, &allocated, FALSE);
 630         pe__set_next_role(rsc, (allocated? RSC_ROLE_UNPROMOTED : RSC_ROLE_STOPPED),
 631                           "unpromoted instance");
 632         g_list_free(allocated);
 633     }
 634 
 635     for (; gIter != NULL; gIter = gIter->next) {
 636         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 637 
 638         set_role_unpromoted(child_rsc, current);
 639     }
 640 }
 641 
 642 static void
 643 set_role_promoted(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 644 {
 645     GList *gIter = rsc->children;
 646 
 647     if (rsc->next_role == RSC_ROLE_UNKNOWN) {
 648         pe__set_next_role(rsc, RSC_ROLE_PROMOTED, "promoted instance");
 649     }
 650 
 651     for (; gIter != NULL; gIter = gIter->next) {
 652         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 653 
 654         set_role_promoted(child_rsc);
 655     }
 656 }
 657 
 658 pe_node_t *
 659 pcmk__set_instance_roles(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 660 {
 661     int promoted = 0;
 662     GList *gIter = NULL;
 663     GList *gIter2 = NULL;
 664     GHashTableIter iter;
 665     pe_node_t *node = NULL;
 666     pe_node_t *chosen = NULL;
 667     enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
 668     char score[33];
 669     size_t len = sizeof(score);
 670     clone_variant_data_t *clone_data = NULL;
 671 
 672     get_clone_variant_data(clone_data, rsc);
 673 
 674     // Repurpose count to track the number of promoted instances allocated
 675     g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 676     while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 677         node->count = 0;
 678     }
 679 
 680     /*
 681      * assign priority
 682      */
 683     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 684         GList *list = NULL;
 685         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 686 
 687         pe_rsc_trace(rsc, "Assigning priority for %s: %s", child_rsc->id,
 688                      role2text(child_rsc->next_role));
 689 
 690         if (child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) {
 691             set_role_unpromoted(child_rsc, true);
 692         }
 693 
 694         chosen = child_rsc->fns->location(child_rsc, &list, FALSE);
 695         if (pcmk__list_of_multiple(list)) {
 696             pcmk__config_err("Cannot promote non-colocated child %s",
 697                              child_rsc->id);
 698         }
 699 
 700         g_list_free(list);
 701         if (chosen == NULL) {
 702             continue;
 703         }
 704 
 705         next_role = child_rsc->fns->state(child_rsc, FALSE);
 706         switch (next_role) {
 707             case RSC_ROLE_STARTED:
 708             case RSC_ROLE_UNKNOWN:
 709                 /*
 710                  * Default to -1 if no value is set
 711                  *
 712                  * This allows instances eligible for promotion to be specified
 713                  * based solely on rsc_location constraints,
 714                  * but prevents anyone from being promoted if
 715                  * neither a constraint nor a promotion score is present
 716                  */
 717                 child_rsc->priority = promotion_score(child_rsc, chosen, -1);
 718                 break;
 719 
 720             case RSC_ROLE_UNPROMOTED:
 721             case RSC_ROLE_STOPPED:
 722                 child_rsc->priority = -INFINITY;
 723                 break;
 724             case RSC_ROLE_PROMOTED:
 725                 /* We will arrive here if we're re-creating actions after a stonith
 726                  */
 727                 break;
 728             default:
 729                 CRM_CHECK(FALSE /* unhandled */ ,
 730                           crm_err("Unknown resource role: %d for %s", next_role, child_rsc->id));
 731         }
 732 
 733         apply_promoted_location(child_rsc, child_rsc->rsc_location, chosen);
 734         apply_promoted_location(child_rsc, rsc->rsc_location, chosen);
 735 
 736         for (gIter2 = child_rsc->rsc_cons; gIter2 != NULL; gIter2 = gIter2->next) {
 737             pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter2->data;
 738 
 739             child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->rsc_rh, cons,
 740                                                data_set);
 741         }
 742 
 743         child_rsc->sort_index = child_rsc->priority;
 744         pe_rsc_trace(rsc, "Assigning priority for %s: %d", child_rsc->id, child_rsc->priority);
 745 
 746         if (next_role == RSC_ROLE_PROMOTED) {
 747             child_rsc->sort_index = INFINITY;
 748         }
 749     }
 750 
 751     pe__show_node_weights(true, rsc, "Pre merge", rsc->allowed_nodes, data_set);
 752     promotion_order(rsc, data_set);
 753 
 754     // Choose the first N eligible instances to be promoted
 755     for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 756         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 757         score2char_stack(child_rsc->sort_index, score, len);
 758 
 759         chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
 760         if (pcmk_is_set(data_set->flags, pe_flag_show_scores) && !pcmk__is_daemon) {
 761             if (data_set->priv != NULL) {
 762                 pcmk__output_t *out = data_set->priv;
 763                 out->message(out, "promotion-score", child_rsc, chosen, score);
 764             }
 765 
 766         } else {
 767             pe_rsc_trace(rsc, "%s promotion score on %s: %s", child_rsc->id,
 768                          (chosen? chosen->details->uname : "none"), score);
 769         }
 770 
 771         chosen = NULL;          /* nuke 'chosen' so that we don't promote more than the
 772                                  * required number of instances
 773                                  */
 774 
 775         if (child_rsc->sort_index < 0) {
 776             pe_rsc_trace(rsc, "Not supposed to promote child: %s", child_rsc->id);
 777 
 778         } else if ((promoted < clone_data->promoted_max)
 779                    || !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
 780             chosen = node_to_be_promoted_on(child_rsc);
 781         }
 782 
 783         pe_rsc_debug(rsc, "%s promotion score: %d", child_rsc->id, child_rsc->priority);
 784 
 785         if (chosen == NULL) {
 786             set_role_unpromoted(child_rsc, false);
 787             continue;
 788 
 789         } else if ((child_rsc->role < RSC_ROLE_PROMOTED)
 790               && !pcmk_is_set(data_set->flags, pe_flag_have_quorum)
 791               && data_set->no_quorum_policy == no_quorum_freeze) {
 792             crm_notice("Resource %s cannot be elevated from %s to %s: no-quorum-policy=freeze",
 793                        child_rsc->id, role2text(child_rsc->role), role2text(child_rsc->next_role));
 794             set_role_unpromoted(child_rsc, false);
 795             continue;
 796         }
 797 
 798         chosen->count++;
 799         pe_rsc_info(rsc, "Promoting %s (%s %s)",
 800                     child_rsc->id, role2text(child_rsc->role), chosen->details->uname);
 801         set_role_promoted(child_rsc);
 802         promoted++;
 803     }
 804 
 805     pe_rsc_info(rsc, "%s: Promoted %d instances of a possible %d",
 806                 rsc->id, promoted, clone_data->promoted_max);
 807 
 808     return NULL;
 809 }
 810 
 811 void
 812 create_promotable_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 813 {
 814     pe_action_t *action = NULL;
 815     GList *gIter = rsc->children;
 816     pe_action_t *action_complete = NULL;
 817     gboolean any_promoting = FALSE;
 818     gboolean any_demoting = FALSE;
 819     pe_resource_t *last_promote_rsc = NULL;
 820     pe_resource_t *last_demote_rsc = NULL;
 821 
 822     clone_variant_data_t *clone_data = NULL;
 823 
 824     get_clone_variant_data(clone_data, rsc);
 825 
 826     pe_rsc_debug(rsc, "Creating actions for %s", rsc->id);
 827 
 828     for (; gIter != NULL; gIter = gIter->next) {
 829         gboolean child_promoting = FALSE;
 830         gboolean child_demoting = FALSE;
 831         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 832 
 833         pe_rsc_trace(rsc, "Creating actions for %s", child_rsc->id);
 834         child_rsc->cmds->create_actions(child_rsc, data_set);
 835         check_promotable_actions(child_rsc, &child_demoting, &child_promoting);
 836 
 837         any_demoting = any_demoting || child_demoting;
 838         any_promoting = any_promoting || child_promoting;
 839         pe_rsc_trace(rsc, "Created actions for %s: %d %d", child_rsc->id, child_promoting,
 840                      child_demoting);
 841     }
 842 
 843     /* promote */
 844     action = create_pseudo_resource_op(rsc, RSC_PROMOTE, !any_promoting, TRUE, data_set);
 845     action_complete = create_pseudo_resource_op(rsc, RSC_PROMOTED, !any_promoting, TRUE, data_set);
 846     action_complete->priority = INFINITY;
 847 
 848     child_promoting_constraints(clone_data, pe_order_optional,
 849                                 rsc, NULL, last_promote_rsc, data_set);
 850 
 851     if (clone_data->promote_notify == NULL) {
 852         clone_data->promote_notify =
 853             create_notification_boundaries(rsc, RSC_PROMOTE, action, action_complete, data_set);
 854     }
 855 
 856     /* demote */
 857     action = create_pseudo_resource_op(rsc, RSC_DEMOTE, !any_demoting, TRUE, data_set);
 858     action_complete = create_pseudo_resource_op(rsc, RSC_DEMOTED, !any_demoting, TRUE, data_set);
 859     action_complete->priority = INFINITY;
 860 
 861     child_demoting_constraints(clone_data, pe_order_optional, rsc, NULL, last_demote_rsc, data_set);
 862 
 863     if (clone_data->demote_notify == NULL) {
 864         clone_data->demote_notify =
 865             create_notification_boundaries(rsc, RSC_DEMOTE, action, action_complete, data_set);
 866 
 867         if (clone_data->promote_notify) {
 868             /* If we ever wanted groups to have notifications we'd need to move this to native_internal_constraints() one day
 869              * Requires exposing *_notify
 870              */
 871             order_actions(clone_data->stop_notify->post_done, clone_data->promote_notify->pre,
 872                           pe_order_optional);
 873             order_actions(clone_data->start_notify->post_done, clone_data->promote_notify->pre,
 874                           pe_order_optional);
 875             order_actions(clone_data->demote_notify->post_done, clone_data->promote_notify->pre,
 876                           pe_order_optional);
 877             order_actions(clone_data->demote_notify->post_done, clone_data->start_notify->pre,
 878                           pe_order_optional);
 879             order_actions(clone_data->demote_notify->post_done, clone_data->stop_notify->pre,
 880                           pe_order_optional);
 881         }
 882     }
 883 
 884     /* restore the correct priority */
 885 
 886     gIter = rsc->children;
 887     for (; gIter != NULL; gIter = gIter->next) {
 888         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 889 
 890         child_rsc->priority = rsc->priority;
 891     }
 892 }
 893 
 894 void
 895 promote_demote_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 896 {
 897     /* global stopped before start */
 898     new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
 899 
 900     /* global stopped before promote */
 901     new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_PROMOTE, pe_order_optional, data_set);
 902 
 903     /* global demoted before start */
 904     new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_START, pe_order_optional, data_set);
 905 
 906     /* global started before promote */
 907     new_rsc_order(rsc, RSC_STARTED, rsc, RSC_PROMOTE, pe_order_optional, data_set);
 908 
 909     /* global demoted before stop */
 910     new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
 911 
 912     /* global demote before demoted */
 913     new_rsc_order(rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, pe_order_optional, data_set);
 914 
 915     /* global demoted before promote */
 916     new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_PROMOTE, pe_order_optional, data_set);
 917 }
 918 
 919 
 920 void
 921 promotable_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 922 {
 923     GList *gIter = rsc->children;
 924     pe_resource_t *last_rsc = NULL;
 925     clone_variant_data_t *clone_data = NULL;
 926 
 927     get_clone_variant_data(clone_data, rsc);
 928 
 929     promote_demote_constraints(rsc, data_set);
 930 
 931     for (; gIter != NULL; gIter = gIter->next) {
 932         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 933 
 934         /* child demote before promote */
 935         new_rsc_order(child_rsc, RSC_DEMOTE, child_rsc, RSC_PROMOTE, pe_order_optional, data_set);
 936 
 937         child_promoting_constraints(clone_data, pe_order_optional,
 938                                     rsc, child_rsc, last_rsc, data_set);
 939 
 940         child_demoting_constraints(clone_data, pe_order_optional,
 941                                    rsc, child_rsc, last_rsc, data_set);
 942 
 943         last_rsc = child_rsc;
 944     }
 945 }
 946 
 947 static void
 948 node_hash_update_one(GHashTable * hash, pe_node_t * other, const char *attr, int score)
     /* [previous][next][first][last][top][bottom][index][help] */
 949 {
 950     GHashTableIter iter;
 951     pe_node_t *node = NULL;
 952     const char *value = NULL;
 953 
 954     if (other == NULL) {
 955         return;
 956 
 957     } else if (attr == NULL) {
 958         attr = CRM_ATTR_UNAME;
 959     }
 960  
 961     value = pe_node_attribute_raw(other, attr);
 962     g_hash_table_iter_init(&iter, hash);
 963     while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 964         const char *tmp = pe_node_attribute_raw(node, attr);
 965 
 966         if (pcmk__str_eq(value, tmp, pcmk__str_casei)) {
 967             crm_trace("%s: %d + %d", node->details->uname, node->weight, other->weight);
 968             node->weight = pe__add_scores(node->weight, score);
 969         }
 970     }
 971 }
 972 
 973 void
 974 promotable_colocation_rh(pe_resource_t *rsc_lh, pe_resource_t *rsc_rh,
     /* [previous][next][first][last][top][bottom][index][help] */
 975                          pcmk__colocation_t *constraint,
 976                          pe_working_set_t *data_set)
 977 {
 978     GList *gIter = NULL;
 979 
 980     if (pcmk_is_set(rsc_lh->flags, pe_rsc_provisional)) {
 981         GList *rhs = NULL;
 982 
 983         for (gIter = rsc_rh->children; gIter != NULL; gIter = gIter->next) {
 984             pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 985             pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
 986             enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, FALSE);
 987 
 988             pe_rsc_trace(rsc_rh, "Processing: %s", child_rsc->id);
 989             if (chosen != NULL && next_role == constraint->role_rh) {
 990                 pe_rsc_trace(rsc_rh, "Applying: %s %s %s %d", child_rsc->id,
 991                              role2text(next_role), chosen->details->uname, constraint->score);
 992                 if (constraint->score < INFINITY) {
 993                     node_hash_update_one(rsc_lh->allowed_nodes, chosen,
 994                                          constraint->node_attribute, constraint->score);
 995                 }
 996                 rhs = g_list_prepend(rhs, chosen);
 997             }
 998         }
 999 
1000         /* Only do this if it's not a promoted-with-promoted colocation. Doing
1001          * this unconditionally would prevent unpromoted instances from being
1002          * started.
1003          */
1004         if ((constraint->role_lh != RSC_ROLE_PROMOTED)
1005             || (constraint->role_rh != RSC_ROLE_PROMOTED)) {
1006 
1007             if (constraint->score >= INFINITY) {
1008                 node_list_exclude(rsc_lh->allowed_nodes, rhs, TRUE);
1009             }
1010         }
1011         g_list_free(rhs);
1012 
1013     } else if (constraint->role_lh == RSC_ROLE_PROMOTED) {
1014         pe_resource_t *rh_child = find_compatible_child(rsc_lh, rsc_rh,
1015                                                         constraint->role_rh,
1016                                                         FALSE, data_set);
1017 
1018         if (rh_child == NULL && constraint->score >= INFINITY) {
1019             pe_rsc_trace(rsc_lh, "%s can't be promoted %s", rsc_lh->id, constraint->id);
1020             rsc_lh->priority = -INFINITY;
1021 
1022         } else if (rh_child != NULL) {
1023             int new_priority = pe__add_scores(rsc_lh->priority,
1024                                               constraint->score);
1025 
1026             pe_rsc_debug(rsc_lh, "Applying %s to %s", constraint->id, rsc_lh->id);
1027             pe_rsc_debug(rsc_lh, "\t%s: %d->%d", rsc_lh->id, rsc_lh->priority, new_priority);
1028             rsc_lh->priority = new_priority;
1029         }
1030     }
1031 
1032     return;
1033 }

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