root/pengine/master.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. master_update_pseudo_status
  4. apply_master_location
  5. can_be_master
  6. sort_master_instance
  7. master_merge_weights
  8. master_promotion_order
  9. filter_anonymous_instance
  10. lookup_master_score
  11. master_score
  12. apply_master_prefs
  13. set_role_slave
  14. set_role_master
  15. master_color
  16. master_create_actions
  17. master_promotion_constraints
  18. master_internal_constraints
  19. node_hash_update_one
  20. master_rsc_colocation_rh
  21. master_append_meta

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

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