This source file includes following definitions.
- pcmk__group_assign
- create_group_pseudo_op
- pcmk__group_create_actions
- member_internal_constraints
- pcmk__group_internal_constraints
- colocate_group_with
- colocate_with_group
- pcmk__group_apply_coloc_score
- pcmk__group_action_flags
- pcmk__group_update_ordered_actions
- pcmk__group_apply_location
- pcmk__group_colocated_resources
- pcmk__with_group_colocations
- pcmk__group_with_colocations
- pcmk__group_add_colocated_node_scores
- pcmk__group_add_utilization
- pcmk__group_shutdown_lock
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdbool.h>
  13 
  14 #include <qb/qbdefs.h>              
  15 
  16 #include <crm/common/xml.h>
  17 
  18 #include <pacemaker-internal.h>
  19 #include "libpacemaker_private.h"
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 pcmk_node_t *
  40 pcmk__group_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer,
     
  41                    bool stop_if_fail)
  42 {
  43     pcmk_node_t *first_assigned_node = NULL;
  44     pcmk_resource_t *first_member = NULL;
  45 
  46     pcmk__assert(pcmk__is_group(rsc));
  47 
  48     if (!pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
  49         return rsc->allocated_to; 
  50     }
  51     if (pcmk_is_set(rsc->flags, pcmk_rsc_assigning)) {
  52         pcmk__rsc_debug(rsc, "Assignment dependency loop detected involving %s",
  53                         rsc->id);
  54         return NULL;
  55     }
  56 
  57     if (rsc->children == NULL) {
  58         
  59         pcmk__clear_rsc_flags(rsc, pcmk_rsc_unassigned);
  60         return NULL;
  61     }
  62 
  63     pcmk__set_rsc_flags(rsc, pcmk_rsc_assigning);
  64     first_member = (pcmk_resource_t *) rsc->children->data;
  65     rsc->role = first_member->role;
  66 
  67     pe__show_node_scores(!pcmk_is_set(rsc->cluster->flags,
  68                                       pcmk_sched_output_scores),
  69                          rsc, __func__, rsc->allowed_nodes, rsc->cluster);
  70 
  71     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
  72         pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
  73         pcmk_node_t *node = NULL;
  74 
  75         pcmk__rsc_trace(rsc, "Assigning group %s member %s",
  76                         rsc->id, member->id);
  77         node = member->cmds->assign(member, prefer, stop_if_fail);
  78         if (first_assigned_node == NULL) {
  79             first_assigned_node = node;
  80         }
  81     }
  82 
  83     pe__set_next_role(rsc, first_member->next_role, "first group member");
  84     pcmk__clear_rsc_flags(rsc, pcmk_rsc_assigning|pcmk_rsc_unassigned);
  85 
  86     if (!pe__group_flag_is_set(rsc, pcmk__group_colocated)) {
  87         return NULL;
  88     }
  89     return first_assigned_node;
  90 }
  91 
  92 
  93 
  94 
  95 
  96 
  97 
  98 
  99 
 100 
 101 static pcmk_action_t *
 102 create_group_pseudo_op(pcmk_resource_t *group, const char *action)
     
 103 {
 104     pcmk_action_t *op = custom_action(group, pcmk__op_key(group->id, action, 0),
 105                                       action, NULL, TRUE, group->cluster);
 106 
 107     pcmk__set_action_flags(op, pcmk_action_pseudo|pcmk_action_runnable);
 108     return op;
 109 }
 110 
 111 
 112 
 113 
 114 
 115 
 116 
 117 void
 118 pcmk__group_create_actions(pcmk_resource_t *rsc)
     
 119 {
 120     pcmk__assert(pcmk__is_group(rsc));
 121 
 122     pcmk__rsc_trace(rsc, "Creating actions for group %s", rsc->id);
 123 
 124     
 125     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 126         pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
 127 
 128         member->cmds->create_actions(member);
 129     }
 130 
 131     
 132     create_group_pseudo_op(rsc, PCMK_ACTION_START);
 133     create_group_pseudo_op(rsc, PCMK_ACTION_RUNNING);
 134     create_group_pseudo_op(rsc, PCMK_ACTION_STOP);
 135     create_group_pseudo_op(rsc, PCMK_ACTION_STOPPED);
 136     if (crm_is_true(g_hash_table_lookup(rsc->meta, PCMK_META_PROMOTABLE))) {
 137         create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTE);
 138         create_group_pseudo_op(rsc, PCMK_ACTION_DEMOTED);
 139         create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTE);
 140         create_group_pseudo_op(rsc, PCMK_ACTION_PROMOTED);
 141     }
 142 }
 143 
 144 
 145 struct member_data {
 146     
 147     bool ordered;
 148     bool colocated;
 149     bool promotable;
 150 
 151     pcmk_resource_t *last_active;
 152     pcmk_resource_t *previous_member;
 153 };
 154 
 155 
 156 
 157 
 158 
 159 
 160 
 161 
 162 static void
 163 member_internal_constraints(gpointer data, gpointer user_data)
     
 164 {
 165     pcmk_resource_t *member = (pcmk_resource_t *) data;
 166     struct member_data *member_data = (struct member_data *) user_data;
 167 
 168     
 169     uint32_t down_flags = pcmk__ar_then_implies_first_graphed;
 170 
 171     
 172     uint32_t post_down_flags = pcmk__ar_first_implies_then_graphed;
 173 
 174     
 175     member->cmds->internal_constraints(member);
 176 
 177     if (member_data->previous_member == NULL) {
 178         
 179         if (member_data->ordered) {
 180             pcmk__set_relation_flags(down_flags, pcmk__ar_ordered);
 181             post_down_flags = pcmk__ar_first_implies_then;
 182         }
 183 
 184     } else if (member_data->colocated) {
 185         uint32_t flags = pcmk__coloc_none;
 186 
 187         if (pcmk_is_set(member->flags, pcmk_rsc_critical)) {
 188             flags |= pcmk__coloc_influence;
 189         }
 190 
 191         
 192         pcmk__new_colocation("#group-members", NULL, PCMK_SCORE_INFINITY,
 193                              member, member_data->previous_member, NULL, NULL,
 194                              flags);
 195     }
 196 
 197     if (member_data->promotable) {
 198         
 199         pcmk__order_resource_actions(member->parent, PCMK_ACTION_DEMOTE,
 200                                      member, PCMK_ACTION_DEMOTE, down_flags);
 201         pcmk__order_resource_actions(member, PCMK_ACTION_DEMOTE,
 202                                      member->parent, PCMK_ACTION_DEMOTED,
 203                                      post_down_flags);
 204 
 205         
 206         pcmk__order_resource_actions(member, PCMK_ACTION_PROMOTE,
 207                                      member->parent, PCMK_ACTION_PROMOTED,
 208                                      pcmk__ar_unrunnable_first_blocks
 209                                      |pcmk__ar_first_implies_then
 210                                      |pcmk__ar_first_implies_then_graphed);
 211         pcmk__order_resource_actions(member->parent, PCMK_ACTION_PROMOTE,
 212                                      member, PCMK_ACTION_PROMOTE,
 213                                      pcmk__ar_then_implies_first_graphed);
 214     }
 215 
 216     
 217     pcmk__order_stops(member->parent, member, down_flags);
 218     pcmk__order_resource_actions(member, PCMK_ACTION_STOP,
 219                                  member->parent, PCMK_ACTION_STOPPED,
 220                                  post_down_flags);
 221 
 222     
 223     pcmk__order_starts(member->parent, member,
 224                        pcmk__ar_then_implies_first_graphed);
 225     pcmk__order_resource_actions(member, PCMK_ACTION_START,
 226                                  member->parent, PCMK_ACTION_RUNNING,
 227                                  pcmk__ar_unrunnable_first_blocks
 228                                  |pcmk__ar_first_implies_then
 229                                  |pcmk__ar_first_implies_then_graphed);
 230 
 231     if (!member_data->ordered) {
 232         pcmk__order_starts(member->parent, member,
 233                            pcmk__ar_first_implies_then
 234                            |pcmk__ar_unrunnable_first_blocks
 235                            |pcmk__ar_then_implies_first_graphed);
 236         if (member_data->promotable) {
 237             pcmk__order_resource_actions(member->parent, PCMK_ACTION_PROMOTE,
 238                                          member, PCMK_ACTION_PROMOTE,
 239                                          pcmk__ar_first_implies_then
 240                                          |pcmk__ar_unrunnable_first_blocks
 241                                          |pcmk__ar_then_implies_first_graphed);
 242         }
 243 
 244     } else if (member_data->previous_member == NULL) {
 245         pcmk__order_starts(member->parent, member, pcmk__ar_none);
 246         if (member_data->promotable) {
 247             pcmk__order_resource_actions(member->parent, PCMK_ACTION_PROMOTE,
 248                                          member, PCMK_ACTION_PROMOTE,
 249                                          pcmk__ar_none);
 250         }
 251 
 252     } else {
 253         
 254 
 255         pcmk__order_starts(member_data->previous_member, member,
 256                            pcmk__ar_first_implies_then
 257                            |pcmk__ar_unrunnable_first_blocks);
 258         pcmk__order_stops(member, member_data->previous_member,
 259                           pcmk__ar_ordered|pcmk__ar_intermediate_stop);
 260 
 261         
 262 
 263 
 264 
 265 
 266 
 267         if ((member->running_on != NULL)
 268             && (member_data->previous_member->running_on == NULL)) {
 269             pcmk__order_resource_actions(member, PCMK_ACTION_STOP,
 270                                          member_data->previous_member,
 271                                          PCMK_ACTION_START,
 272                                          pcmk__ar_then_implies_first
 273                                          |pcmk__ar_unrunnable_first_blocks);
 274         }
 275 
 276         if (member_data->promotable) {
 277             pcmk__order_resource_actions(member_data->previous_member,
 278                                          PCMK_ACTION_PROMOTE, member,
 279                                          PCMK_ACTION_PROMOTE,
 280                                          pcmk__ar_first_implies_then
 281                                          |pcmk__ar_unrunnable_first_blocks);
 282             pcmk__order_resource_actions(member, PCMK_ACTION_DEMOTE,
 283                                          member_data->previous_member,
 284                                          PCMK_ACTION_DEMOTE, pcmk__ar_ordered);
 285         }
 286     }
 287 
 288     
 289     if (member->running_on != NULL) {
 290         if (member_data->ordered && (member_data->previous_member != NULL)
 291             && (member_data->previous_member->running_on == NULL)
 292             && (member_data->last_active != NULL)
 293             && (member_data->last_active->running_on != NULL)) {
 294             pcmk__order_stops(member, member_data->last_active,
 295                               pcmk__ar_ordered);
 296         }
 297         member_data->last_active = member;
 298     }
 299 
 300     member_data->previous_member = member;
 301 }
 302 
 303 
 304 
 305 
 306 
 307 
 308 
 309 void
 310 pcmk__group_internal_constraints(pcmk_resource_t *rsc)
     
 311 {
 312     struct member_data member_data = { false, };
 313     const pcmk_resource_t *top = NULL;
 314 
 315     pcmk__assert(pcmk__is_group(rsc));
 316 
 317     
 318 
 319 
 320     pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP,
 321                                  rsc, PCMK_ACTION_STOPPED,
 322                                  pcmk__ar_unrunnable_first_blocks);
 323     pcmk__order_resource_actions(rsc, PCMK_ACTION_STOPPED,
 324                                  rsc, PCMK_ACTION_START,
 325                                  pcmk__ar_ordered);
 326     pcmk__order_resource_actions(rsc, PCMK_ACTION_START,
 327                                  rsc, PCMK_ACTION_RUNNING,
 328                                  pcmk__ar_unrunnable_first_blocks);
 329 
 330     top = pe__const_top_resource(rsc, false);
 331 
 332     member_data.ordered = pe__group_flag_is_set(rsc, pcmk__group_ordered);
 333     member_data.colocated = pe__group_flag_is_set(rsc, pcmk__group_colocated);
 334     member_data.promotable = pcmk_is_set(top->flags, pcmk_rsc_promotable);
 335     g_list_foreach(rsc->children, member_internal_constraints, &member_data);
 336 }
 337 
 338 
 339 
 340 
 341 
 342 
 343 
 344 
 345 
 346 
 347 
 348 
 349 
 350 
 351 
 352 static int
 353 colocate_group_with(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
     
 354                     const pcmk__colocation_t *colocation)
 355 {
 356     int priority_delta = 0;
 357 
 358     if (dependent->children == NULL) {
 359         return 0;
 360     }
 361 
 362     pcmk__rsc_trace(primary, "Processing %s (group %s with %s) for dependent",
 363                     colocation->id, dependent->id, primary->id);
 364 
 365     if (pe__group_flag_is_set(dependent, pcmk__group_colocated)) {
 366         
 367         pcmk_resource_t *member = dependent->children->data;
 368 
 369         priority_delta = member->cmds->apply_coloc_score(member, primary,
 370                                                          colocation, true);
 371 
 372     } else {
 373         if (colocation->score >= PCMK_SCORE_INFINITY) {
 374             pcmk__config_err("%s: Cannot perform mandatory colocation between "
 375                              "non-colocated group and %s",
 376                              dependent->id, primary->id);
 377             return 0;
 378         }
 379 
 380         
 381         for (GList *iter = dependent->children; iter != NULL;
 382              iter = iter->next) {
 383 
 384             pcmk_resource_t *member = iter->data;
 385             int instance_delta = member->cmds->apply_coloc_score(member,
 386                                                                  primary,
 387                                                                  colocation,
 388                                                                  false);
 389 
 390             
 391 
 392 
 393 
 394 
 395 
 396             priority_delta = pcmk__add_scores(priority_delta, instance_delta);
 397         }
 398     }
 399 
 400     if (priority_delta != 0) {
 401         dependent->priority = pcmk__add_scores(priority_delta,
 402                                                dependent->priority);
 403 
 404         pcmk__rsc_trace(dependent,
 405                         "Applied %s to %s promotion priority "
 406                         "(now %s after %s %d)",
 407                         colocation->id, dependent->id,
 408                         pcmk_readable_score(dependent->priority),
 409                         ((priority_delta > 0)? "adding" : "subtracting"),
 410                         QB_ABS(priority_delta));
 411     }
 412     return priority_delta;
 413 }
 414 
 415 
 416 
 417 
 418 
 419 
 420 
 421 
 422 
 423 
 424 
 425 
 426 
 427 
 428 
 429 static int
 430 colocate_with_group(pcmk_resource_t *dependent, const pcmk_resource_t *primary,
     
 431                     const pcmk__colocation_t *colocation)
 432 {
 433     int priority_delta = 0;
 434     const pcmk_resource_t *member = NULL;
 435 
 436     pcmk__rsc_trace(primary,
 437                     "Processing colocation %s (%s with group %s) for primary",
 438                     colocation->id, dependent->id, primary->id);
 439 
 440     if (pcmk_is_set(primary->flags, pcmk_rsc_unassigned)) {
 441         return 0;
 442     }
 443 
 444     if (pe__group_flag_is_set(primary, pcmk__group_colocated)) {
 445 
 446         if (colocation->score >= PCMK_SCORE_INFINITY) {
 447             
 448 
 449 
 450 
 451             member = pe__last_group_member(primary);
 452         } else if (primary->children != NULL) {
 453             
 454 
 455 
 456 
 457             member = (pcmk_resource_t *) primary->children->data;
 458         }
 459         if (member == NULL) {
 460             return 0;   
 461         }
 462 
 463         return member->cmds->apply_coloc_score(dependent, member, colocation,
 464                                                false);
 465     }
 466 
 467     if (colocation->score >= PCMK_SCORE_INFINITY) {
 468         pcmk__config_err("%s: Cannot perform mandatory colocation with"
 469                          " non-colocated group %s",
 470                          dependent->id, primary->id);
 471         return 0;
 472     }
 473 
 474     
 475     for (const GList *iter = primary->children; iter != NULL;
 476          iter = iter->next) {
 477 
 478         int instance_delta = 0;
 479 
 480         member = iter->data;
 481         instance_delta = member->cmds->apply_coloc_score(dependent, member,
 482                                                          colocation, false);
 483         priority_delta = pcmk__add_scores(priority_delta, instance_delta);
 484     }
 485     return priority_delta;
 486 }
 487 
 488 
 489 
 490 
 491 
 492 
 493 
 494 
 495 
 496 
 497 
 498 
 499 
 500 
 501 
 502 
 503 int
 504 pcmk__group_apply_coloc_score(pcmk_resource_t *dependent,
     
 505                               const pcmk_resource_t *primary,
 506                               const pcmk__colocation_t *colocation,
 507                               bool for_dependent)
 508 {
 509     pcmk__assert((dependent != NULL) && (primary != NULL)
 510                  && (colocation != NULL));
 511 
 512     if (for_dependent) {
 513         return colocate_group_with(dependent, primary, colocation);
 514 
 515     } else {
 516         
 517         pcmk__assert(pcmk__is_primitive(dependent));
 518 
 519         return colocate_with_group(dependent, primary, colocation);
 520     }
 521 }
 522 
 523 
 524 
 525 
 526 
 527 
 528 
 529 
 530 
 531 
 532 uint32_t
 533 pcmk__group_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
     
 534 {
 535     
 536     uint32_t flags = pcmk_action_optional
 537                      |pcmk_action_runnable
 538                      |pcmk_action_pseudo;
 539 
 540     pcmk__assert(action != NULL);
 541 
 542     
 543     for (GList *iter = action->rsc->children; iter != NULL; iter = iter->next) {
 544         pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
 545 
 546         
 547         enum action_tasks task = get_complex_task(member, action->task);
 548         const char *task_s = pcmk_action_text(task);
 549         pcmk_action_t *member_action = find_first_action(member->actions, NULL,
 550                                                          task_s, node);
 551 
 552         if (member_action != NULL) {
 553             uint32_t member_flags = member->cmds->action_flags(member_action,
 554                                                                node);
 555 
 556             
 557             if (pcmk_is_set(flags, pcmk_action_optional)
 558                 && !pcmk_is_set(member_flags, pcmk_action_optional)) {
 559                 pcmk__rsc_trace(action->rsc, "%s is mandatory because %s is",
 560                                 action->uuid, member_action->uuid);
 561                 pcmk__clear_raw_action_flags(flags, "group action",
 562                                              pcmk_action_optional);
 563                 pcmk__clear_action_flags(action, pcmk_action_optional);
 564             }
 565 
 566             
 567             if (!pcmk__str_eq(task_s, action->task, pcmk__str_none)
 568                 && pcmk_is_set(flags, pcmk_action_runnable)
 569                 && !pcmk_is_set(member_flags, pcmk_action_runnable)) {
 570 
 571                 pcmk__rsc_trace(action->rsc, "%s is unrunnable because %s is",
 572                                 action->uuid, member_action->uuid);
 573                 pcmk__clear_raw_action_flags(flags, "group action",
 574                                              pcmk_action_runnable);
 575                 pcmk__clear_action_flags(action, pcmk_action_runnable);
 576             }
 577 
 578         
 579 
 580 
 581         } else if ((task != pcmk_action_stop) && (task != pcmk_action_demote)) {
 582             pcmk__rsc_trace(action->rsc,
 583                             "%s is not runnable because %s will not %s",
 584                             action->uuid, member->id, task_s);
 585             pcmk__clear_raw_action_flags(flags, "group action",
 586                                          pcmk_action_runnable);
 587         }
 588     }
 589 
 590     return flags;
 591 }
 592 
 593 
 594 
 595 
 596 
 597 
 598 
 599 
 600 
 601 
 602 
 603 
 604 
 605 
 606 
 607 
 608 
 609 
 610 
 611 
 612 
 613 
 614 
 615 uint32_t
 616 pcmk__group_update_ordered_actions(pcmk_action_t *first, pcmk_action_t *then,
     
 617                                    const pcmk_node_t *node, uint32_t flags,
 618                                    uint32_t filter, uint32_t type,
 619                                    pcmk_scheduler_t *scheduler)
 620 {
 621     uint32_t changed = pcmk__updated_none;
 622 
 623     
 624     pcmk__assert((first != NULL) && (then != NULL) && (then->rsc != NULL)
 625                  && (scheduler != NULL));
 626 
 627     
 628     changed |= pcmk__update_ordered_actions(first, then, node, flags, filter,
 629                                             type, scheduler);
 630 
 631     
 632     for (GList *iter = then->rsc->children; iter != NULL; iter = iter->next) {
 633         pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
 634 
 635         pcmk_action_t *member_action = find_first_action(member->actions, NULL,
 636                                                          then->task, node);
 637 
 638         if (member_action != NULL) {
 639             changed |= member->cmds->update_ordered_actions(first,
 640                                                             member_action, node,
 641                                                             flags, filter, type,
 642                                                             scheduler);
 643         }
 644     }
 645     return changed;
 646 }
 647 
 648 
 649 
 650 
 651 
 652 
 653 
 654 
 655 void
 656 pcmk__group_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
     
 657 {
 658     GList *node_list_orig = NULL;
 659     GList *node_list_copy = NULL;
 660 
 661     pcmk__assert(pcmk__is_group(rsc) && (location != NULL));
 662 
 663     
 664     node_list_orig = location->nodes;
 665 
 666     
 667     node_list_copy  = pcmk__copy_node_list(node_list_orig, true);
 668 
 669     
 670 
 671 
 672 
 673     pcmk__apply_location(rsc, location);
 674 
 675     
 676     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 677         pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
 678 
 679         if (pe__group_flag_is_set(rsc, pcmk__group_colocated)
 680             && (iter != rsc->children)) {
 681             
 682 
 683 
 684 
 685 
 686 
 687 
 688 
 689 
 690 
 691 
 692 
 693             location->nodes = node_list_copy;
 694         }
 695 
 696         member->cmds->apply_location(member, location);
 697     }
 698 
 699     location->nodes = node_list_orig;
 700     g_list_free_full(node_list_copy, free);
 701 }
 702 
 703 
 704 GList *
 705 pcmk__group_colocated_resources(const pcmk_resource_t *rsc,
     
 706                                 const pcmk_resource_t *orig_rsc,
 707                                 GList *colocated_rscs)
 708 {
 709     const pcmk_resource_t *member = NULL;
 710 
 711     pcmk__assert(pcmk__is_group(rsc));
 712 
 713     if (orig_rsc == NULL) {
 714         orig_rsc = rsc;
 715     }
 716 
 717     if (pe__group_flag_is_set(rsc, pcmk__group_colocated)
 718         || pcmk__is_clone(rsc->parent)) {
 719         
 720 
 721 
 722 
 723         colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
 724         for (const GList *iter = rsc->children;
 725              iter != NULL; iter = iter->next) {
 726 
 727             member = (const pcmk_resource_t *) iter->data;
 728             colocated_rscs = member->cmds->colocated_resources(member, orig_rsc,
 729                                                                colocated_rscs);
 730         }
 731 
 732     } else if (rsc->children != NULL) {
 733         
 734 
 735 
 736         colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc,
 737                                                    colocated_rscs);
 738     }
 739 
 740     return colocated_rscs;
 741 }
 742 
 743 
 744 void
 745 pcmk__with_group_colocations(const pcmk_resource_t *rsc,
     
 746                              const pcmk_resource_t *orig_rsc, GList **list)
 747 
 748 {
 749     pcmk__assert((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
 750 
 751     
 752     if (rsc->children == NULL) {
 753         return;
 754     }
 755 
 756     
 757 
 758 
 759 
 760     if ((orig_rsc != rsc) && (orig_rsc != pe__last_group_member(rsc))) {
 761         return;
 762     }
 763 
 764     pcmk__rsc_trace(rsc, "Adding 'with %s' colocations to list for %s",
 765                     rsc->id, orig_rsc->id);
 766 
 767     
 768     pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
 769 
 770     
 771     if (rsc->parent != NULL) {
 772         rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc,
 773                                                  list);
 774     }
 775 
 776     if (!pe__group_flag_is_set(rsc, pcmk__group_colocated)) {
 777         
 778         return;
 779     }
 780 
 781     
 782     for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 783         const pcmk_resource_t *member = iter->data;
 784 
 785         if (member != orig_rsc) {
 786             member->cmds->with_this_colocations(member, orig_rsc, list);
 787         }
 788     }
 789 }
 790 
 791 
 792 void
 793 pcmk__group_with_colocations(const pcmk_resource_t *rsc,
     
 794                              const pcmk_resource_t *orig_rsc, GList **list)
 795 {
 796     const pcmk_resource_t *member = NULL;
 797 
 798     pcmk__assert((orig_rsc != NULL) && (list != NULL) && pcmk__is_group(rsc));
 799 
 800     
 801     if (rsc->children == NULL) {
 802         return;
 803     }
 804 
 805     
 806 
 807 
 808     if ((rsc == orig_rsc)
 809         || (orig_rsc == (const pcmk_resource_t *) rsc->children->data)) {
 810         pcmk__rsc_trace(rsc, "Adding '%s with' colocations to list for %s",
 811                         rsc->id, orig_rsc->id);
 812 
 813         
 814         pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
 815 
 816         
 817         if (rsc->parent != NULL) {
 818             rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc,
 819                                                      list);
 820         }
 821 
 822         if (!pe__group_flag_is_set(rsc, pcmk__group_colocated)) {
 823             
 824             return;
 825         }
 826 
 827         
 828         for (const GList *iter = rsc->children;
 829              iter != NULL; iter = iter->next) {
 830             member = iter->data;
 831             if (member != orig_rsc) {
 832                 member->cmds->this_with_colocations(member, orig_rsc, list);
 833             }
 834         }
 835         return;
 836     }
 837 
 838     
 839 
 840 
 841 
 842 
 843     for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 844         member = iter->data;
 845         if (orig_rsc == member) {
 846             break; 
 847         }
 848 
 849         if (!pcmk_is_set(member->flags, pcmk_rsc_managed)) {
 850             crm_trace("Adding mandatory '%s with' colocations to list for "
 851                       "member %s because earlier member %s is unmanaged",
 852                       rsc->id, orig_rsc->id, member->id);
 853             for (const GList *cons_iter = rsc->rsc_cons; cons_iter != NULL;
 854                  cons_iter = cons_iter->next) {
 855                 const pcmk__colocation_t *colocation = NULL;
 856 
 857                 colocation = (const pcmk__colocation_t *) cons_iter->data;
 858                 if (colocation->score == PCMK_SCORE_INFINITY) {
 859                     pcmk__add_this_with(list, colocation, orig_rsc);
 860                 }
 861             }
 862             
 863             break;
 864         }
 865     }
 866 }
 867 
 868 
 869 
 870 
 871 
 872 
 873 
 874 
 875 
 876 
 877 
 878 
 879 
 880 
 881 
 882 
 883 
 884 
 885 
 886 
 887 
 888 
 889 
 890 
 891 
 892 
 893 
 894 
 895 
 896 
 897 
 898 void
 899 pcmk__group_add_colocated_node_scores(pcmk_resource_t *source_rsc,
     
 900                                       const pcmk_resource_t *target_rsc,
 901                                       const char *log_id, GHashTable **nodes,
 902                                       const pcmk__colocation_t *colocation,
 903                                       float factor, uint32_t flags)
 904 {
 905     pcmk_resource_t *member = NULL;
 906 
 907     pcmk__assert(pcmk__is_group(source_rsc) && (nodes != NULL)
 908                  && ((colocation != NULL)
 909                      || ((target_rsc == NULL) && (*nodes == NULL))));
 910 
 911     if (log_id == NULL) {
 912         log_id = source_rsc->id;
 913     }
 914 
 915     
 916     if (pcmk_is_set(source_rsc->flags, pcmk_rsc_updating_nodes)) {
 917         pcmk__rsc_info(source_rsc, "%s: Breaking dependency loop at %s",
 918                        log_id, source_rsc->id);
 919         return;
 920     }
 921     pcmk__set_rsc_flags(source_rsc, pcmk_rsc_updating_nodes);
 922 
 923     
 924     if (source_rsc->children == NULL) {
 925         return;
 926     }
 927 
 928     
 929 
 930 
 931 
 932 
 933 
 934 
 935 
 936 
 937 
 938     if (*nodes == NULL) {
 939         member = pe__last_group_member(source_rsc);
 940     } else {
 941         member = source_rsc->children->data;
 942     }
 943     pcmk__rsc_trace(source_rsc, "%s: Merging scores from group %s using member %s "
 944                     "(at %.6f)", log_id, source_rsc->id, member->id, factor);
 945     member->cmds->add_colocated_node_scores(member, target_rsc, log_id, nodes,
 946                                             colocation, factor, flags);
 947     pcmk__clear_rsc_flags(source_rsc, pcmk_rsc_updating_nodes);
 948 }
 949 
 950 
 951 void
 952 pcmk__group_add_utilization(const pcmk_resource_t *rsc,
     
 953                             const pcmk_resource_t *orig_rsc, GList *all_rscs,
 954                             GHashTable *utilization)
 955 {
 956     pcmk_resource_t *member = NULL;
 957 
 958     pcmk__assert((orig_rsc != NULL) && (utilization != NULL)
 959                  && pcmk__is_group(rsc));
 960 
 961     if (!pcmk_is_set(rsc->flags, pcmk_rsc_unassigned)) {
 962         return;
 963     }
 964 
 965     pcmk__rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
 966                     orig_rsc->id, rsc->id);
 967     if (pe__group_flag_is_set(rsc, pcmk__group_colocated)
 968         || pcmk__is_clone(rsc->parent)) {
 969         
 970         for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 971             member = (pcmk_resource_t *) iter->data;
 972 
 973             if (pcmk_is_set(member->flags, pcmk_rsc_unassigned)
 974                 && (g_list_find(all_rscs, member) == NULL)) {
 975                 member->cmds->add_utilization(member, orig_rsc, all_rscs,
 976                                               utilization);
 977             }
 978         }
 979 
 980     } else if (rsc->children != NULL) {
 981         
 982         member = (pcmk_resource_t *) rsc->children->data;
 983         if ((member != NULL)
 984             && pcmk_is_set(member->flags, pcmk_rsc_unassigned)
 985             && (g_list_find(all_rscs, member) == NULL)) {
 986 
 987             member->cmds->add_utilization(member, orig_rsc, all_rscs,
 988                                           utilization);
 989         }
 990     }
 991 }
 992 
 993 void
 994 pcmk__group_shutdown_lock(pcmk_resource_t *rsc)
     
 995 {
 996     pcmk__assert(pcmk__is_group(rsc));
 997 
 998     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 999         pcmk_resource_t *member = (pcmk_resource_t *) iter->data;
1000 
1001         member->cmds->shutdown_lock(member);
1002     }
1003 }