This source file includes following definitions.
- pcmk__rsc_agent_changed
- add_rsc_if_matching
- pcmk__rscs_matching_id
- set_allocation_methods_for_rsc
- pcmk__set_allocation_methods
- pcmk__colocated_resources
- pcmk__noop_add_graph_meta
- pcmk__output_resource_actions
- pcmk__finalize_assignment
- pcmk__assign_resource
- pcmk__unassign_resource
- pcmk__threshold_reached
- convert_const_pointer
- get_node_weight
- cmp_resources
- pcmk__sort_resources
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdlib.h>
  13 #include <string.h>
  14 #include <crm/msg_xml.h>
  15 #include <pacemaker-internal.h>
  16 
  17 #include "libpacemaker_private.h"
  18 
  19 
  20 static resource_alloc_functions_t allocation_methods[] = {
  21     {
  22         pcmk__primitive_assign,
  23         pcmk__primitive_create_actions,
  24         pcmk__probe_rsc_on_node,
  25         pcmk__primitive_internal_constraints,
  26         pcmk__primitive_apply_coloc_score,
  27         pcmk__colocated_resources,
  28         pcmk__with_primitive_colocations,
  29         pcmk__primitive_with_colocations,
  30         pcmk__add_colocated_node_scores,
  31         pcmk__apply_location,
  32         pcmk__primitive_action_flags,
  33         pcmk__update_ordered_actions,
  34         pcmk__output_resource_actions,
  35         pcmk__add_rsc_actions_to_graph,
  36         pcmk__primitive_add_graph_meta,
  37         pcmk__primitive_add_utilization,
  38         pcmk__primitive_shutdown_lock,
  39     },
  40     {
  41         pcmk__group_assign,
  42         pcmk__group_create_actions,
  43         pcmk__probe_rsc_on_node,
  44         pcmk__group_internal_constraints,
  45         pcmk__group_apply_coloc_score,
  46         pcmk__group_colocated_resources,
  47         pcmk__with_group_colocations,
  48         pcmk__group_with_colocations,
  49         pcmk__group_add_colocated_node_scores,
  50         pcmk__group_apply_location,
  51         pcmk__group_action_flags,
  52         pcmk__group_update_ordered_actions,
  53         pcmk__output_resource_actions,
  54         pcmk__add_rsc_actions_to_graph,
  55         pcmk__noop_add_graph_meta,
  56         pcmk__group_add_utilization,
  57         pcmk__group_shutdown_lock,
  58     },
  59     {
  60         pcmk__clone_assign,
  61         clone_create_actions,
  62         clone_create_probe,
  63         clone_internal_constraints,
  64         pcmk__clone_apply_coloc_score,
  65         pcmk__colocated_resources,
  66         pcmk__with_clone_colocations,
  67         pcmk__clone_with_colocations,
  68         pcmk__add_colocated_node_scores,
  69         clone_rsc_location,
  70         clone_action_flags,
  71         pcmk__instance_update_ordered_actions,
  72         pcmk__output_resource_actions,
  73         clone_expand,
  74         clone_append_meta,
  75         pcmk__clone_add_utilization,
  76         pcmk__clone_shutdown_lock,
  77     },
  78     {
  79         pcmk__bundle_allocate,
  80         pcmk__bundle_create_actions,
  81         pcmk__bundle_create_probe,
  82         pcmk__bundle_internal_constraints,
  83         pcmk__bundle_apply_coloc_score,
  84         pcmk__colocated_resources,
  85         pcmk__with_bundle_colocations,
  86         pcmk__bundle_with_colocations,
  87         pcmk__add_colocated_node_scores,
  88         pcmk__bundle_rsc_location,
  89         pcmk__bundle_action_flags,
  90         pcmk__instance_update_ordered_actions,
  91         pcmk__output_bundle_actions,
  92         pcmk__bundle_expand,
  93         pcmk__noop_add_graph_meta,
  94         pcmk__bundle_add_utilization,
  95         pcmk__bundle_shutdown_lock,
  96     }
  97 };
  98 
  99 
 100 
 101 
 102 
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 bool
 111 pcmk__rsc_agent_changed(pe_resource_t *rsc, pe_node_t *node,
     
 112                         const xmlNode *rsc_entry, bool active_on_node)
 113 {
 114     bool changed = false;
 115     const char *attr_list[] = {
 116         XML_ATTR_TYPE,
 117         XML_AGENT_ATTR_CLASS,
 118         XML_AGENT_ATTR_PROVIDER
 119     };
 120 
 121     for (int i = 0; i < PCMK__NELEM(attr_list); i++) {
 122         const char *value = crm_element_value(rsc->xml, attr_list[i]);
 123         const char *old_value = crm_element_value(rsc_entry, attr_list[i]);
 124 
 125         if (!pcmk__str_eq(value, old_value, pcmk__str_none)) {
 126             changed = true;
 127             trigger_unfencing(rsc, node, "Device definition changed", NULL,
 128                               rsc->cluster);
 129             if (active_on_node) {
 130                 crm_notice("Forcing restart of %s on %s "
 131                            "because %s changed from '%s' to '%s'",
 132                            rsc->id, pe__node_name(node), attr_list[i],
 133                            pcmk__s(old_value, ""), pcmk__s(value, ""));
 134             }
 135         }
 136     }
 137     if (changed && active_on_node) {
 138         
 139         custom_action(rsc, stop_key(rsc), CRMD_ACTION_STOP, node, FALSE, TRUE,
 140                       rsc->cluster);
 141         pe__set_resource_flags(rsc, pe_rsc_start_pending);
 142     }
 143     return changed;
 144 }
 145 
 146 
 147 
 148 
 149 
 150 
 151 
 152 
 153 
 154 
 155 
 156 static GList *
 157 add_rsc_if_matching(GList *result, pe_resource_t *rsc, const char *id)
     
 158 {
 159     if ((strcmp(rsc->id, id) == 0)
 160         || ((rsc->clone_name != NULL) && (strcmp(rsc->clone_name, id) == 0))) {
 161         result = g_list_prepend(result, rsc);
 162     }
 163     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 164         pe_resource_t *child = (pe_resource_t *) iter->data;
 165 
 166         result = add_rsc_if_matching(result, child, id);
 167     }
 168     return result;
 169 }
 170 
 171 
 172 
 173 
 174 
 175 
 176 
 177 
 178 
 179 
 180 
 181 
 182 GList *
 183 pcmk__rscs_matching_id(const char *id, const pe_working_set_t *data_set)
     
 184 {
 185     GList *result = NULL;
 186 
 187     CRM_CHECK((id != NULL) && (data_set != NULL), return NULL);
 188     for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
 189         result = add_rsc_if_matching(result, (pe_resource_t *) iter->data, id);
 190     }
 191     return result;
 192 }
 193 
 194 
 195 
 196 
 197 
 198 
 199 
 200 
 201 static void
 202 set_allocation_methods_for_rsc(pe_resource_t *rsc, void *ignored)
     
 203 {
 204     rsc->cmds = &allocation_methods[rsc->variant];
 205     g_list_foreach(rsc->children, (GFunc) set_allocation_methods_for_rsc, NULL);
 206 }
 207 
 208 
 209 
 210 
 211 
 212 
 213 
 214 void
 215 pcmk__set_allocation_methods(pe_working_set_t *data_set)
     
 216 {
 217     g_list_foreach(data_set->resources, (GFunc) set_allocation_methods_for_rsc,
 218                    NULL);
 219 }
 220 
 221 
 222 GList *
 223 pcmk__colocated_resources(const pe_resource_t *rsc, const pe_resource_t *orig_rsc,
     
 224                           GList *colocated_rscs)
 225 {
 226     const GList *iter = NULL;
 227     GList *colocations = NULL;
 228 
 229     if (orig_rsc == NULL) {
 230         orig_rsc = rsc;
 231     }
 232 
 233     if ((rsc == NULL) || (g_list_find(colocated_rscs, rsc) != NULL)) {
 234         return colocated_rscs;
 235     }
 236 
 237     pe_rsc_trace(orig_rsc, "%s is in colocation chain with %s",
 238                  rsc->id, orig_rsc->id);
 239     colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
 240 
 241     
 242     colocations = pcmk__this_with_colocations(rsc);
 243     for (iter = colocations; iter != NULL; iter = iter->next) {
 244         const pcmk__colocation_t *constraint = iter->data;
 245         const pe_resource_t *primary = constraint->primary;
 246 
 247         if (primary == orig_rsc) {
 248             continue; 
 249         }
 250 
 251         if ((constraint->score == INFINITY) &&
 252             (pcmk__colocation_affects(rsc, primary, constraint,
 253                                       true) == pcmk__coloc_affects_location)) {
 254 
 255             colocated_rscs = primary->cmds->colocated_resources(primary,
 256                                                                 orig_rsc,
 257                                                                 colocated_rscs);
 258         }
 259     }
 260     g_list_free(colocations);
 261 
 262     
 263     colocations = pcmk__with_this_colocations(rsc);
 264     for (iter = colocations; iter != NULL; iter = iter->next) {
 265         const pcmk__colocation_t *constraint = iter->data;
 266         const pe_resource_t *dependent = constraint->dependent;
 267 
 268         if (dependent == orig_rsc) {
 269             continue; 
 270         }
 271 
 272         if (pe_rsc_is_clone(rsc) && !pe_rsc_is_clone(dependent)) {
 273             continue; 
 274         }
 275 
 276         if ((constraint->score == INFINITY) &&
 277             (pcmk__colocation_affects(dependent, rsc, constraint,
 278                                       true) == pcmk__coloc_affects_location)) {
 279 
 280             colocated_rscs = dependent->cmds->colocated_resources(dependent,
 281                                                                   orig_rsc,
 282                                                                   colocated_rscs);
 283         }
 284     }
 285     g_list_free(colocations);
 286 
 287     return colocated_rscs;
 288 }
 289 
 290 
 291 void
 292 pcmk__noop_add_graph_meta(const pe_resource_t *rsc, xmlNode *xml)
     
 293 {
 294 }
 295 
 296 void
 297 pcmk__output_resource_actions(pe_resource_t *rsc)
     
 298 {
 299     pcmk__output_t *out = rsc->cluster->priv;
 300 
 301     pe_node_t *next = NULL;
 302     pe_node_t *current = NULL;
 303 
 304     if (rsc->children != NULL) {
 305         for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 306             pe_resource_t *child = (pe_resource_t *) iter->data;
 307 
 308             child->cmds->output_actions(child);
 309         }
 310         return;
 311     }
 312 
 313     next = rsc->allocated_to;
 314     if (rsc->running_on) {
 315         current = pe__current_node(rsc);
 316         if (rsc->role == RSC_ROLE_STOPPED) {
 317             
 318 
 319 
 320             rsc->role = RSC_ROLE_STARTED;
 321         }
 322     }
 323 
 324     if ((current == NULL) && pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
 325         
 326         return;
 327     }
 328 
 329     out->message(out, "rsc-action", rsc, current, next);
 330 }
 331 
 332 
 333 
 334 
 335 
 336 
 337 
 338 
 339 
 340 
 341 
 342 
 343 
 344 
 345 
 346 
 347 
 348 
 349 
 350 
 351 
 352 
 353 bool
 354 pcmk__finalize_assignment(pe_resource_t *rsc, pe_node_t *chosen, bool force)
     
 355 {
 356     pcmk__output_t *out = rsc->cluster->priv;
 357 
 358     CRM_ASSERT(rsc->variant == pe_native);
 359 
 360     if (!force && (chosen != NULL)) {
 361         if ((chosen->weight < 0)
 362             
 363             || (!pcmk__node_available(chosen, true, false)
 364                 && !pe__is_guest_node(chosen))) {
 365 
 366             crm_debug("All nodes for resource %s are unavailable, unclean or "
 367                       "shutting down (%s can%s run resources, with weight %d)",
 368                       rsc->id, pe__node_name(chosen),
 369                       (pcmk__node_available(chosen, true, false)? "" : "not"),
 370                       chosen->weight);
 371             pe__set_next_role(rsc, RSC_ROLE_STOPPED, "node availability");
 372             chosen = NULL;
 373         }
 374     }
 375 
 376     pcmk__unassign_resource(rsc);
 377     pe__clear_resource_flags(rsc, pe_rsc_provisional);
 378 
 379     if (chosen == NULL) {
 380         crm_debug("Could not allocate a node for %s", rsc->id);
 381         pe__set_next_role(rsc, RSC_ROLE_STOPPED, "unable to allocate");
 382 
 383         for (GList *iter = rsc->actions; iter != NULL; iter = iter->next) {
 384             pe_action_t *op = (pe_action_t *) iter->data;
 385 
 386             crm_debug("Updating %s for allocation failure", op->uuid);
 387 
 388             if (pcmk__str_eq(op->task, RSC_STOP, pcmk__str_casei)) {
 389                 pe__clear_action_flags(op, pe_action_optional);
 390 
 391             } else if (pcmk__str_eq(op->task, RSC_START, pcmk__str_casei)) {
 392                 pe__clear_action_flags(op, pe_action_runnable);
 393                 
 394 
 395             } else {
 396                 
 397                 const char *interval_ms_s = NULL;
 398                 const char *target_rc_s = NULL;
 399                 char *rc_stopped = pcmk__itoa(PCMK_OCF_NOT_RUNNING);
 400 
 401                 interval_ms_s = g_hash_table_lookup(op->meta,
 402                                                     XML_LRM_ATTR_INTERVAL_MS);
 403                 target_rc_s = g_hash_table_lookup(op->meta,
 404                                                   XML_ATTR_TE_TARGET_RC);
 405                 if ((interval_ms_s != NULL)
 406                     && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_none)
 407                     && !pcmk__str_eq(rc_stopped, target_rc_s, pcmk__str_none)) {
 408                     pe__clear_action_flags(op, pe_action_runnable);
 409                 }
 410                 free(rc_stopped);
 411             }
 412         }
 413         return false;
 414     }
 415 
 416     crm_debug("Assigning %s to %s", rsc->id, pe__node_name(chosen));
 417     rsc->allocated_to = pe__copy_node(chosen);
 418 
 419     chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc,
 420                                                     rsc);
 421     chosen->details->num_resources++;
 422     chosen->count++;
 423     pcmk__consume_node_capacity(chosen->details->utilization, rsc);
 424 
 425     if (pcmk_is_set(rsc->cluster->flags, pe_flag_show_utilization)) {
 426         out->message(out, "resource-util", rsc, chosen, __func__);
 427     }
 428     return true;
 429 }
 430 
 431 
 432 
 433 
 434 
 435 
 436 
 437 
 438 
 439 
 440 
 441 
 442 
 443 
 444 
 445 
 446 
 447 
 448 
 449 
 450 
 451 bool
 452 pcmk__assign_resource(pe_resource_t *rsc, pe_node_t *node, bool force)
     
 453 {
 454     bool changed = false;
 455 
 456     if (rsc->children == NULL) {
 457         if (rsc->allocated_to != NULL) {
 458             changed = true;
 459         }
 460         pcmk__finalize_assignment(rsc, node, force);
 461 
 462     } else {
 463         for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 464             pe_resource_t *child_rsc = (pe_resource_t *) iter->data;
 465 
 466             changed |= pcmk__assign_resource(child_rsc, node, force);
 467         }
 468     }
 469     return changed;
 470 }
 471 
 472 
 473 
 474 
 475 
 476 
 477 
 478 
 479 
 480 
 481 
 482 void
 483 pcmk__unassign_resource(pe_resource_t *rsc)
     
 484 {
 485     pe_node_t *old = rsc->allocated_to;
 486 
 487     if (old == NULL) {
 488         return;
 489     }
 490 
 491     crm_info("Unassigning %s from %s", rsc->id, pe__node_name(old));
 492     pe__set_resource_flags(rsc, pe_rsc_provisional);
 493     rsc->allocated_to = NULL;
 494 
 495     
 496 
 497 
 498     old->details->allocated_rsc = g_list_remove(old->details->allocated_rsc,
 499                                                 rsc);
 500     old->details->num_resources--;
 501     pcmk__release_node_capacity(old->details->utilization, rsc);
 502     free(old);
 503 }
 504 
 505 
 506 
 507 
 508 
 509 
 510 
 511 
 512 
 513 
 514 
 515 
 516 bool
 517 pcmk__threshold_reached(pe_resource_t *rsc, const pe_node_t *node,
     
 518                         pe_resource_t **failed)
 519 {
 520     int fail_count, remaining_tries;
 521     pe_resource_t *rsc_to_ban = rsc;
 522 
 523     
 524     if (rsc->migration_threshold == 0) {
 525         return false;
 526     }
 527 
 528     
 529     if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
 530         return false;
 531     }
 532 
 533     
 534     fail_count = pe_get_failcount(node, rsc, NULL,
 535                                   pe_fc_effective|pe_fc_fillers, NULL);
 536     if (fail_count <= 0) {
 537         return false;
 538     }
 539 
 540     
 541     if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
 542         rsc_to_ban = uber_parent(rsc);
 543     }
 544 
 545     
 546     remaining_tries = rsc->migration_threshold - fail_count;
 547 
 548     if (remaining_tries <= 0) {
 549         crm_warn("%s cannot run on %s due to reaching migration threshold "
 550                  "(clean up resource to allow again)"
 551                  CRM_XS " failures=%d migration-threshold=%d",
 552                  rsc_to_ban->id, pe__node_name(node), fail_count,
 553                  rsc->migration_threshold);
 554         if (failed != NULL) {
 555             *failed = rsc_to_ban;
 556         }
 557         return true;
 558     }
 559 
 560     crm_info("%s can fail %d more time%s on "
 561              "%s before reaching migration threshold (%d)",
 562              rsc_to_ban->id, remaining_tries, pcmk__plural_s(remaining_tries),
 563              pe__node_name(node), rsc->migration_threshold);
 564     return false;
 565 }
 566 
 567 static void *
 568 convert_const_pointer(const void *ptr)
     
 569 {
 570     
 571     return (void *)ptr;
 572 }
 573 
 574 
 575 
 576 
 577 
 578 
 579 
 580 
 581 
 582 
 583 static int
 584 get_node_weight(const pe_node_t *node, GHashTable *nodes)
     
 585 {
 586     pe_node_t *weighted_node = NULL;
 587 
 588     if ((node != NULL) && (nodes != NULL)) {
 589         weighted_node = g_hash_table_lookup(nodes, node->details->id);
 590     }
 591     return (weighted_node == NULL)? -INFINITY : weighted_node->weight;
 592 }
 593 
 594 
 595 
 596 
 597 
 598 
 599 
 600 
 601 
 602 
 603 
 604 
 605 static gint
 606 cmp_resources(gconstpointer a, gconstpointer b, gpointer data)
     
 607 {
 608     const pe_resource_t *resource1 = a;
 609     const pe_resource_t *resource2 = b;
 610     const GList *nodes = (const GList *) data;
 611 
 612     int rc = 0;
 613     int r1_weight = -INFINITY;
 614     int r2_weight = -INFINITY;
 615     pe_node_t *r1_node = NULL;
 616     pe_node_t *r2_node = NULL;
 617     GHashTable *r1_nodes = NULL;
 618     GHashTable *r2_nodes = NULL;
 619     const char *reason = NULL;
 620 
 621     
 622     reason = "priority";
 623     r1_weight = resource1->priority;
 624     r2_weight = resource2->priority;
 625     if (r1_weight > r2_weight) {
 626         rc = -1;
 627         goto done;
 628     }
 629     if (r1_weight < r2_weight) {
 630         rc = 1;
 631         goto done;
 632     }
 633 
 634     
 635     reason = "no node list";
 636     if (nodes == NULL) {
 637         goto done;
 638     }
 639 
 640     
 641     resource1->cmds->add_colocated_node_scores(convert_const_pointer(resource1),
 642                                                resource1->id, &r1_nodes, NULL,
 643                                                1, pcmk__coloc_select_this_with);
 644     resource2->cmds->add_colocated_node_scores(convert_const_pointer(resource2),
 645                                                resource2->id, &r2_nodes, NULL,
 646                                                1, pcmk__coloc_select_this_with);
 647     pe__show_node_weights(true, NULL, resource1->id, r1_nodes,
 648                           resource1->cluster);
 649     pe__show_node_weights(true, NULL, resource2->id, r2_nodes,
 650                           resource2->cluster);
 651 
 652     
 653     reason = "current location";
 654     if (resource1->running_on != NULL) {
 655         r1_node = pe__current_node(resource1);
 656     }
 657     if (resource2->running_on != NULL) {
 658         r2_node = pe__current_node(resource2);
 659     }
 660     r1_weight = get_node_weight(r1_node, r1_nodes);
 661     r2_weight = get_node_weight(r2_node, r2_nodes);
 662     if (r1_weight > r2_weight) {
 663         rc = -1;
 664         goto done;
 665     }
 666     if (r1_weight < r2_weight) {
 667         rc = 1;
 668         goto done;
 669     }
 670 
 671     
 672     reason = "score";
 673     for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
 674         const pe_node_t *node = (const pe_node_t *) iter->data;
 675 
 676         r1_weight = get_node_weight(node, r1_nodes);
 677         r2_weight = get_node_weight(node, r2_nodes);
 678         if (r1_weight > r2_weight) {
 679             rc = -1;
 680             goto done;
 681         }
 682         if (r1_weight < r2_weight) {
 683             rc = 1;
 684             goto done;
 685         }
 686     }
 687 
 688 done:
 689     crm_trace("%s (%d)%s%s %c %s (%d)%s%s: %s",
 690               resource1->id, r1_weight,
 691               ((r1_node == NULL)? "" : " on "),
 692               ((r1_node == NULL)? "" : r1_node->details->id),
 693               ((rc < 0)? '>' : ((rc > 0)? '<' : '=')),
 694               resource2->id, r2_weight,
 695               ((r2_node == NULL)? "" : " on "),
 696               ((r2_node == NULL)? "" : r2_node->details->id),
 697               reason);
 698     if (r1_nodes != NULL) {
 699         g_hash_table_destroy(r1_nodes);
 700     }
 701     if (r2_nodes != NULL) {
 702         g_hash_table_destroy(r2_nodes);
 703     }
 704     return rc;
 705 }
 706 
 707 
 708 
 709 
 710 
 711 
 712 
 713 void
 714 pcmk__sort_resources(pe_working_set_t *data_set)
     
 715 {
 716     GList *nodes = g_list_copy(data_set->nodes);
 717 
 718     nodes = pcmk__sort_nodes(nodes, NULL);
 719     data_set->resources = g_list_sort_with_data(data_set->resources,
 720                                                 cmp_resources, nodes);
 721     g_list_free(nodes);
 722 }