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

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