root/lib/pacemaker/pcmk_sched_location.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_node_score
  2. generate_location_rule
  3. unpack_rsc_location
  4. unpack_simple_location
  5. unpack_location_tags
  6. unpack_location_set
  7. pcmk__unpack_location
  8. pcmk__new_location
  9. pcmk__apply_locations
  10. pcmk__apply_location

   1 /*
   2  * Copyright 2004-2023 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdbool.h>
  13 #include <glib.h>
  14 
  15 #include <crm/crm.h>
  16 #include <crm/pengine/status.h>
  17 #include <crm/pengine/rules.h>
  18 #include <pacemaker-internal.h>
  19 
  20 #include "libpacemaker_private.h"
  21 
  22 static int
  23 get_node_score(const char *rule, const char *score, bool raw,
     /* [previous][next][first][last][top][bottom][index][help] */
  24                pcmk_node_t *node, pcmk_resource_t *rsc)
  25 {
  26     int score_f = 0;
  27 
  28     if (score == NULL) {
  29         pe_err("Rule %s: no score specified.  Assuming 0.", rule);
  30 
  31     } else if (raw) {
  32         score_f = char2score(score);
  33 
  34     } else {
  35         const char *attr_score = NULL;
  36 
  37         attr_score = pe__node_attribute_calculated(node, score, rsc,
  38                                                    pcmk__rsc_node_current,
  39                                                    false);
  40 
  41         if (attr_score == NULL) {
  42             crm_debug("Rule %s: %s did not have a value for %s",
  43                       rule, pe__node_name(node), score);
  44             score_f = -INFINITY;
  45 
  46         } else {
  47             crm_debug("Rule %s: %s had value %s for %s",
  48                       rule, pe__node_name(node), attr_score, score);
  49             score_f = char2score(attr_score);
  50         }
  51     }
  52     return score_f;
  53 }
  54 
  55 static pe__location_t *
  56 generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml,
     /* [previous][next][first][last][top][bottom][index][help] */
  57                        const char *discovery, crm_time_t *next_change,
  58                        pe_re_match_data_t *re_match_data)
  59 {
  60     const char *rule_id = NULL;
  61     const char *score = NULL;
  62     const char *boolean = NULL;
  63     const char *role = NULL;
  64 
  65     GList *iter = NULL;
  66     GList *nodes = NULL;
  67 
  68     bool do_and = true;
  69     bool accept = true;
  70     bool raw_score = true;
  71     bool score_allocated = false;
  72 
  73     pe__location_t *location_rule = NULL;
  74 
  75     rule_xml = expand_idref(rule_xml, rsc->cluster->input);
  76     if (rule_xml == NULL) {
  77         return NULL;
  78     }
  79 
  80     rule_id = crm_element_value(rule_xml, XML_ATTR_ID);
  81     boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP);
  82     role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE);
  83 
  84     crm_trace("Processing rule: %s", rule_id);
  85 
  86     if ((role != NULL) && (text2role(role) == pcmk_role_unknown)) {
  87         pe_err("Bad role specified for %s: %s", rule_id, role);
  88         return NULL;
  89     }
  90 
  91     score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE);
  92     if (score == NULL) {
  93         score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE);
  94         if (score != NULL) {
  95             raw_score = false;
  96         }
  97     }
  98     if (pcmk__str_eq(boolean, "or", pcmk__str_casei)) {
  99         do_and = false;
 100     }
 101 
 102     location_rule = pcmk__new_location(rule_id, rsc, 0, discovery, NULL);
 103 
 104     if (location_rule == NULL) {
 105         return NULL;
 106     }
 107 
 108     if ((re_match_data != NULL) && (re_match_data->nregs > 0)
 109         && (re_match_data->pmatch[0].rm_so != -1) && !raw_score) {
 110 
 111         char *result = pe_expand_re_matches(score, re_match_data);
 112 
 113         if (result != NULL) {
 114             score = result;
 115             score_allocated = true;
 116         }
 117     }
 118 
 119     if (role != NULL) {
 120         crm_trace("Setting role filter: %s", role);
 121         location_rule->role_filter = text2role(role);
 122         if (location_rule->role_filter == pcmk_role_unpromoted) {
 123             /* Any promotable clone cannot be promoted without being in the
 124              * unpromoted role first. Ergo, any constraint for the unpromoted
 125              * role applies to every role.
 126              */
 127             location_rule->role_filter = pcmk_role_unknown;
 128         }
 129     }
 130     if (do_and) {
 131         nodes = pcmk__copy_node_list(rsc->cluster->nodes, true);
 132         for (iter = nodes; iter != NULL; iter = iter->next) {
 133             pcmk_node_t *node = iter->data;
 134 
 135             node->weight = get_node_score(rule_id, score, raw_score, node, rsc);
 136         }
 137     }
 138 
 139     for (iter = rsc->cluster->nodes; iter != NULL; iter = iter->next) {
 140         int score_f = 0;
 141         pcmk_node_t *node = iter->data;
 142         pe_match_data_t match_data = {
 143             .re = re_match_data,
 144             .params = pe_rsc_params(rsc, node, rsc->cluster),
 145             .meta = rsc->meta,
 146         };
 147 
 148         accept = pe_test_rule(rule_xml, node->details->attrs, pcmk_role_unknown,
 149                               rsc->cluster->now, next_change, &match_data);
 150 
 151         crm_trace("Rule %s %s on %s", ID(rule_xml), accept? "passed" : "failed",
 152                   pe__node_name(node));
 153 
 154         score_f = get_node_score(rule_id, score, raw_score, node, rsc);
 155 
 156         if (accept) {
 157             pcmk_node_t *local = pe_find_node_id(nodes, node->details->id);
 158 
 159             if ((local == NULL) && do_and) {
 160                 continue;
 161 
 162             } else if (local == NULL) {
 163                 local = pe__copy_node(node);
 164                 nodes = g_list_append(nodes, local);
 165             }
 166 
 167             if (!do_and) {
 168                 local->weight = pcmk__add_scores(local->weight, score_f);
 169             }
 170             crm_trace("%s has score %s after %s", pe__node_name(node),
 171                       pcmk_readable_score(local->weight), rule_id);
 172 
 173         } else if (do_and && !accept) {
 174             // Remove it
 175             pcmk_node_t *delete = pe_find_node_id(nodes, node->details->id);
 176 
 177             if (delete != NULL) {
 178                 nodes = g_list_remove(nodes, delete);
 179                 crm_trace("%s did not match", pe__node_name(node));
 180             }
 181             free(delete);
 182         }
 183     }
 184 
 185     if (score_allocated) {
 186         free((char *)score);
 187     }
 188 
 189     location_rule->node_list_rh = nodes;
 190     if (location_rule->node_list_rh == NULL) {
 191         crm_trace("No matching nodes for rule %s", rule_id);
 192         return NULL;
 193     }
 194 
 195     crm_trace("%s: %d nodes matched",
 196               rule_id, g_list_length(location_rule->node_list_rh));
 197     return location_rule;
 198 }
 199 
 200 static void
 201 unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, const char *role,
     /* [previous][next][first][last][top][bottom][index][help] */
 202                     const char *score, pe_re_match_data_t *re_match_data)
 203 {
 204     pe__location_t *location = NULL;
 205     const char *rsc_id = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
 206     const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
 207     const char *node = crm_element_value(xml_obj, XML_CIB_TAG_NODE);
 208     const char *discovery = crm_element_value(xml_obj,
 209                                               XML_LOCATION_ATTR_DISCOVERY);
 210 
 211     if (rsc == NULL) {
 212         pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
 213                           "does not exist", id, rsc_id);
 214         return;
 215     }
 216 
 217     if (score == NULL) {
 218         score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
 219     }
 220 
 221     if ((node != NULL) && (score != NULL)) {
 222         int score_i = char2score(score);
 223         pcmk_node_t *match = pe_find_node(rsc->cluster->nodes, node);
 224 
 225         if (!match) {
 226             return;
 227         }
 228         location = pcmk__new_location(id, rsc, score_i, discovery, match);
 229 
 230     } else {
 231         bool empty = true;
 232         crm_time_t *next_change = crm_time_new_undefined();
 233 
 234         /* This loop is logically parallel to pe_evaluate_rules(), except
 235          * instead of checking whether any rule is active, we set up location
 236          * constraints for each active rule.
 237          */
 238         for (xmlNode *rule_xml = first_named_child(xml_obj, XML_TAG_RULE);
 239              rule_xml != NULL; rule_xml = crm_next_same_xml(rule_xml)) {
 240             empty = false;
 241             crm_trace("Unpacking %s/%s", id, ID(rule_xml));
 242             generate_location_rule(rsc, rule_xml, discovery, next_change,
 243                                    re_match_data);
 244         }
 245 
 246         if (empty) {
 247             pcmk__config_err("Ignoring constraint '%s' because it contains "
 248                              "no rules", id);
 249         }
 250 
 251         /* If there is a point in the future when the evaluation of a rule will
 252          * change, make sure the scheduler is re-run by that time.
 253          */
 254         if (crm_time_is_defined(next_change)) {
 255             time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change);
 256 
 257             pe__update_recheck_time(t, rsc->cluster,
 258                                     "location rule evaluation");
 259         }
 260         crm_time_free(next_change);
 261         return;
 262     }
 263 
 264     if (role == NULL) {
 265         role = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
 266     }
 267 
 268     if ((location != NULL) && (role != NULL)) {
 269         if (text2role(role) == pcmk_role_unknown) {
 270             pe_err("Invalid constraint %s: Bad role %s", id, role);
 271             return;
 272 
 273         } else {
 274             enum rsc_role_e r = text2role(role);
 275             switch (r) {
 276                 case pcmk_role_unknown:
 277                 case pcmk_role_started:
 278                 case pcmk_role_unpromoted:
 279                     /* Applies to all */
 280                     location->role_filter = pcmk_role_unknown;
 281                     break;
 282                 default:
 283                     location->role_filter = r;
 284                     break;
 285             }
 286         }
 287     }
 288 }
 289 
 290 static void
 291 unpack_simple_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
     /* [previous][next][first][last][top][bottom][index][help] */
 292 {
 293     const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
 294     const char *value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
 295 
 296     if (value) {
 297         pcmk_resource_t *rsc;
 298 
 299         rsc = pcmk__find_constraint_resource(scheduler->resources, value);
 300         unpack_rsc_location(xml_obj, rsc, NULL, NULL, NULL);
 301     }
 302 
 303     value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE_PATTERN);
 304     if (value) {
 305         regex_t *r_patt = calloc(1, sizeof(regex_t));
 306         bool invert = false;
 307 
 308         if (value[0] == '!') {
 309             value++;
 310             invert = true;
 311         }
 312 
 313         if (regcomp(r_patt, value, REG_EXTENDED) != 0) {
 314             pcmk__config_err("Ignoring constraint '%s' because "
 315                              XML_LOC_ATTR_SOURCE_PATTERN
 316                              " has invalid value '%s'", id, value);
 317             free(r_patt);
 318             return;
 319         }
 320 
 321         for (GList *iter = scheduler->resources; iter != NULL;
 322              iter = iter->next) {
 323 
 324             pcmk_resource_t *r = iter->data;
 325             int nregs = 0;
 326             regmatch_t *pmatch = NULL;
 327             int status;
 328 
 329             if (r_patt->re_nsub > 0) {
 330                 nregs = r_patt->re_nsub + 1;
 331             } else {
 332                 nregs = 1;
 333             }
 334             pmatch = calloc(nregs, sizeof(regmatch_t));
 335 
 336             status = regexec(r_patt, r->id, nregs, pmatch, 0);
 337 
 338             if (!invert && (status == 0)) {
 339                 pe_re_match_data_t re_match_data = {
 340                                                 .string = r->id,
 341                                                 .nregs = nregs,
 342                                                 .pmatch = pmatch
 343                                                };
 344 
 345                 crm_debug("'%s' matched '%s' for %s", r->id, value, id);
 346                 unpack_rsc_location(xml_obj, r, NULL, NULL, &re_match_data);
 347 
 348             } else if (invert && (status != 0)) {
 349                 crm_debug("'%s' is an inverted match of '%s' for %s",
 350                           r->id, value, id);
 351                 unpack_rsc_location(xml_obj, r, NULL, NULL, NULL);
 352 
 353             } else {
 354                 crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
 355             }
 356 
 357             free(pmatch);
 358         }
 359 
 360         regfree(r_patt);
 361         free(r_patt);
 362     }
 363 }
 364 
 365 // \return Standard Pacemaker return code
 366 static int
 367 unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
     /* [previous][next][first][last][top][bottom][index][help] */
 368                      pcmk_scheduler_t *scheduler)
 369 {
 370     const char *id = NULL;
 371     const char *rsc_id = NULL;
 372     const char *state = NULL;
 373     pcmk_resource_t *rsc = NULL;
 374     pcmk_tag_t *tag = NULL;
 375     xmlNode *rsc_set = NULL;
 376 
 377     *expanded_xml = NULL;
 378 
 379     CRM_CHECK(xml_obj != NULL, return EINVAL);
 380 
 381     id = ID(xml_obj);
 382     if (id == NULL) {
 383         pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
 384                          xml_obj->name);
 385         return pcmk_rc_unpack_error;
 386     }
 387 
 388     // Check whether there are any resource sets with template or tag references
 389     *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
 390     if (*expanded_xml != NULL) {
 391         crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
 392         return pcmk_rc_ok;
 393     }
 394 
 395     rsc_id = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
 396     if (rsc_id == NULL) {
 397         return pcmk_rc_ok;
 398     }
 399 
 400     if (!pcmk__valid_resource_or_tag(scheduler, rsc_id, &rsc, &tag)) {
 401         pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
 402                          "valid resource or tag", id, rsc_id);
 403         return pcmk_rc_unpack_error;
 404 
 405     } else if (rsc != NULL) {
 406         // No template is referenced
 407         return pcmk_rc_ok;
 408     }
 409 
 410     state = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
 411 
 412     *expanded_xml = copy_xml(xml_obj);
 413 
 414     // Convert any template or tag reference into constraint resource_set
 415     if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, XML_LOC_ATTR_SOURCE,
 416                           false, scheduler)) {
 417         free_xml(*expanded_xml);
 418         *expanded_xml = NULL;
 419         return pcmk_rc_unpack_error;
 420     }
 421 
 422     if (rsc_set != NULL) {
 423         if (state != NULL) {
 424             // Move "rsc-role" into converted resource_set as "role" attribute
 425             crm_xml_add(rsc_set, "role", state);
 426             xml_remove_prop(*expanded_xml, XML_RULE_ATTR_ROLE);
 427         }
 428         crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
 429 
 430     } else {
 431         // No sets
 432         free_xml(*expanded_xml);
 433         *expanded_xml = NULL;
 434     }
 435 
 436     return pcmk_rc_ok;
 437 }
 438 
 439 // \return Standard Pacemaker return code
 440 static int
 441 unpack_location_set(xmlNode *location, xmlNode *set,
     /* [previous][next][first][last][top][bottom][index][help] */
 442                     pcmk_scheduler_t *scheduler)
 443 {
 444     xmlNode *xml_rsc = NULL;
 445     pcmk_resource_t *resource = NULL;
 446     const char *set_id;
 447     const char *role;
 448     const char *local_score;
 449 
 450     CRM_CHECK(set != NULL, return EINVAL);
 451 
 452     set_id = ID(set);
 453     if (set_id == NULL) {
 454         pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_SET " without "
 455                          XML_ATTR_ID " in constraint '%s'",
 456                          pcmk__s(ID(location), "(missing ID)"));
 457         return pcmk_rc_unpack_error;
 458     }
 459 
 460     role = crm_element_value(set, "role");
 461     local_score = crm_element_value(set, XML_RULE_ATTR_SCORE);
 462 
 463     for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
 464          xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
 465 
 466         resource = pcmk__find_constraint_resource(scheduler->resources,
 467                                                   ID(xml_rsc));
 468         if (resource == NULL) {
 469             pcmk__config_err("%s: No resource found for %s",
 470                              set_id, ID(xml_rsc));
 471             return pcmk_rc_unpack_error;
 472         }
 473 
 474         unpack_rsc_location(location, resource, role, local_score, NULL);
 475     }
 476 
 477     return pcmk_rc_ok;
 478 }
 479 
 480 void
 481 pcmk__unpack_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
     /* [previous][next][first][last][top][bottom][index][help] */
 482 {
 483     xmlNode *set = NULL;
 484     bool any_sets = false;
 485 
 486     xmlNode *orig_xml = NULL;
 487     xmlNode *expanded_xml = NULL;
 488 
 489     if (unpack_location_tags(xml_obj, &expanded_xml, scheduler) != pcmk_rc_ok) {
 490         return;
 491     }
 492 
 493     if (expanded_xml) {
 494         orig_xml = xml_obj;
 495         xml_obj = expanded_xml;
 496     }
 497 
 498     for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
 499          set = crm_next_same_xml(set)) {
 500 
 501         any_sets = true;
 502         set = expand_idref(set, scheduler->input);
 503         if ((set == NULL) // Configuration error, message already logged
 504             || (unpack_location_set(xml_obj, set, scheduler) != pcmk_rc_ok)) {
 505 
 506             if (expanded_xml) {
 507                 free_xml(expanded_xml);
 508             }
 509             return;
 510         }
 511     }
 512 
 513     if (expanded_xml) {
 514         free_xml(expanded_xml);
 515         xml_obj = orig_xml;
 516     }
 517 
 518     if (!any_sets) {
 519         unpack_simple_location(xml_obj, scheduler);
 520     }
 521 }
 522 
 523 /*!
 524  * \internal
 525  * \brief Add a new location constraint to scheduler data
 526  *
 527  * \param[in]     id             XML ID of location constraint
 528  * \param[in,out] rsc            Resource in location constraint
 529  * \param[in]     node_score     Constraint score
 530  * \param[in]     discover_mode  Resource discovery option for constraint
 531  * \param[in]     node           Node in constraint (or NULL if rule-based)
 532  *
 533  * \return Newly allocated location constraint
 534  * \note The result will be added to the cluster (via \p rsc) and should not be
 535  *       freed separately.
 536  */
 537 pe__location_t *
 538 pcmk__new_location(const char *id, pcmk_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 539                    int node_score, const char *discover_mode, pcmk_node_t *node)
 540 {
 541     pe__location_t *new_con = NULL;
 542 
 543     if (id == NULL) {
 544         pe_err("Invalid constraint: no ID specified");
 545         return NULL;
 546 
 547     } else if (rsc == NULL) {
 548         pe_err("Invalid constraint %s: no resource specified", id);
 549         return NULL;
 550 
 551     } else if (node == NULL) {
 552         CRM_CHECK(node_score == 0, return NULL);
 553     }
 554 
 555     new_con = calloc(1, sizeof(pe__location_t));
 556     if (new_con != NULL) {
 557         new_con->id = strdup(id);
 558         new_con->rsc_lh = rsc;
 559         new_con->node_list_rh = NULL;
 560         new_con->role_filter = pcmk_role_unknown;
 561 
 562         if (pcmk__str_eq(discover_mode, "always",
 563                          pcmk__str_null_matches|pcmk__str_casei)) {
 564             new_con->discover_mode = pcmk_probe_always;
 565 
 566         } else if (pcmk__str_eq(discover_mode, "never", pcmk__str_casei)) {
 567             new_con->discover_mode = pcmk_probe_never;
 568 
 569         } else if (pcmk__str_eq(discover_mode, "exclusive", pcmk__str_casei)) {
 570             new_con->discover_mode = pcmk_probe_exclusive;
 571             rsc->exclusive_discover = TRUE;
 572 
 573         } else {
 574             pe_err("Invalid " XML_LOCATION_ATTR_DISCOVERY " value %s "
 575                    "in location constraint", discover_mode);
 576         }
 577 
 578         if (node != NULL) {
 579             pcmk_node_t *copy = pe__copy_node(node);
 580 
 581             copy->weight = node_score;
 582             new_con->node_list_rh = g_list_prepend(NULL, copy);
 583         }
 584 
 585         rsc->cluster->placement_constraints = g_list_prepend(
 586             rsc->cluster->placement_constraints, new_con);
 587         rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
 588     }
 589 
 590     return new_con;
 591 }
 592 
 593 /*!
 594  * \internal
 595  * \brief Apply all location constraints
 596  *
 597  * \param[in,out] scheduler  Scheduler data
 598  */
 599 void
 600 pcmk__apply_locations(pcmk_scheduler_t *scheduler)
     /* [previous][next][first][last][top][bottom][index][help] */
 601 {
 602     for (GList *iter = scheduler->placement_constraints;
 603          iter != NULL; iter = iter->next) {
 604         pe__location_t *location = iter->data;
 605 
 606         location->rsc_lh->cmds->apply_location(location->rsc_lh, location);
 607     }
 608 }
 609 
 610 /*!
 611  * \internal
 612  * \brief Apply a location constraint to a resource's allowed node scores
 613  *
 614  * \param[in,out] rsc         Resource to apply constraint to
 615  * \param[in,out] location    Location constraint to apply
 616  *
 617  * \note This does not consider the resource's children, so the resource's
 618  *       apply_location() method should be used instead in most cases.
 619  */
 620 void
 621 pcmk__apply_location(pcmk_resource_t *rsc, pe__location_t *location)
     /* [previous][next][first][last][top][bottom][index][help] */
 622 {
 623     bool need_role = false;
 624 
 625     CRM_ASSERT((rsc != NULL) && (location != NULL));
 626 
 627     // If a role was specified, ensure constraint is applicable
 628     need_role = (location->role_filter > pcmk_role_unknown);
 629     if (need_role && (location->role_filter != rsc->next_role)) {
 630         pe_rsc_trace(rsc,
 631                      "Not applying %s to %s because role will be %s not %s",
 632                      location->id, rsc->id, role2text(rsc->next_role),
 633                      role2text(location->role_filter));
 634         return;
 635     }
 636 
 637     if (location->node_list_rh == NULL) {
 638         pe_rsc_trace(rsc, "Not applying %s to %s because no nodes match",
 639                      location->id, rsc->id);
 640         return;
 641     }
 642 
 643     pe_rsc_trace(rsc, "Applying %s%s%s to %s", location->id,
 644                  (need_role? " for role " : ""),
 645                  (need_role? role2text(location->role_filter) : ""), rsc->id);
 646 
 647     for (GList *iter = location->node_list_rh;
 648          iter != NULL; iter = iter->next) {
 649 
 650         pcmk_node_t *node = iter->data;
 651         pcmk_node_t *allowed_node = g_hash_table_lookup(rsc->allowed_nodes,
 652                                                         node->details->id);
 653 
 654         if (allowed_node == NULL) {
 655             pe_rsc_trace(rsc, "* = %d on %s",
 656                          node->weight, pe__node_name(node));
 657             allowed_node = pe__copy_node(node);
 658             g_hash_table_insert(rsc->allowed_nodes,
 659                                 (gpointer) allowed_node->details->id,
 660                                 allowed_node);
 661         } else {
 662             pe_rsc_trace(rsc, "* + %d on %s",
 663                          node->weight, pe__node_name(node));
 664             allowed_node->weight = pcmk__add_scores(allowed_node->weight,
 665                                                     node->weight);
 666         }
 667 
 668         if (allowed_node->rsc_discover_mode < location->discover_mode) {
 669             if (location->discover_mode == pcmk_probe_exclusive) {
 670                 rsc->exclusive_discover = TRUE;
 671             }
 672             /* exclusive > never > always... always is default */
 673             allowed_node->rsc_discover_mode = location->discover_mode;
 674         }
 675     }
 676 }

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