root/lib/pacemaker/pcmk_sched_group.c

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

DEFINITIONS

This source file includes following definitions.
  1. expand_group_colocations
  2. pcmk__group_allocate
  3. group_create_actions
  4. group_update_pseudo_status
  5. group_internal_constraints
  6. group_rsc_colocation_lh
  7. group_rsc_colocation_rh
  8. group_action_flags
  9. group_update_actions
  10. group_rsc_location
  11. group_expand
  12. pcmk__group_merge_weights
  13. group_append_meta
  14. pcmk__group_colocated_resources
  15. pcmk__group_add_utilization
  16. pcmk__group_shutdown_lock

   1 /*
   2  * Copyright 2004-2021 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 
  14 #include <crm/msg_xml.h>
  15 
  16 #include <pacemaker-internal.h>
  17 
  18 #include "libpacemaker_private.h"
  19 
  20 #define VARIANT_GROUP 1
  21 #include <lib/pengine/variant.h>
  22 
  23 /*!
  24  * \internal
  25  * \brief Expand a group's colocations to its members
  26  *
  27  * \param[in,out] rsc  Group resource
  28  */
  29 static void
  30 expand_group_colocations(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32     group_variant_data_t *group_data = NULL;
  33     pe_resource_t *member = NULL;
  34     bool any_unmanaged = false;
  35 
  36     get_group_variant_data(group_data, rsc);
  37 
  38     // Treat "group with R" colocations as "first member with R"
  39     member = group_data->first_child;
  40     member->rsc_cons = g_list_concat(member->rsc_cons, rsc->rsc_cons);
  41 
  42 
  43     /* The above works for the whole group because each group member is
  44      * colocated with the previous one.
  45      *
  46      * However, there is a special case when a group has a mandatory colocation
  47      * with a resource that can't start. In that case,
  48      * pcmk__block_colocated_starts() will ensure that dependent resources in
  49      * mandatory colocations (i.e. the first member for groups) can't start
  50      * either. But if any group member is unmanaged and already started, the
  51      * internal group colocations are no longer sufficient to make that apply to
  52      * later members.
  53      *
  54      * To handle that case, add mandatory colocations to each member after the
  55      * first.
  56      */
  57     any_unmanaged = !pcmk_is_set(member->flags, pe_rsc_managed);
  58     for (GList *item = rsc->children->next; item != NULL; item = item->next) {
  59         member = item->data;
  60         if (any_unmanaged) {
  61             for (GList *cons_iter = rsc->rsc_cons; cons_iter != NULL;
  62                  cons_iter = cons_iter->next) {
  63 
  64                 pcmk__colocation_t *constraint = (pcmk__colocation_t *) cons_iter->data;
  65 
  66                 if (constraint->score == INFINITY) {
  67                     member->rsc_cons = g_list_prepend(member->rsc_cons, constraint);
  68                 }
  69             }
  70         } else if (!pcmk_is_set(member->flags, pe_rsc_managed)) {
  71             any_unmanaged = true;
  72         }
  73     }
  74 
  75     rsc->rsc_cons = NULL;
  76 
  77     // Treat "R with group" colocations as "R with last member"
  78     member = group_data->last_child;
  79     member->rsc_cons_lhs = g_list_concat(member->rsc_cons_lhs,
  80                                          rsc->rsc_cons_lhs);
  81     rsc->rsc_cons_lhs = NULL;
  82 }
  83 
  84 pe_node_t *
  85 pcmk__group_allocate(pe_resource_t *rsc, pe_node_t *prefer,
     /* [previous][next][first][last][top][bottom][index][help] */
  86                      pe_working_set_t *data_set)
  87 {
  88     pe_node_t *node = NULL;
  89     pe_node_t *group_node = NULL;
  90     GList *gIter = NULL;
  91     group_variant_data_t *group_data = NULL;
  92 
  93     get_group_variant_data(group_data, rsc);
  94 
  95     if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
  96         return rsc->allocated_to;
  97     }
  98     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
  99         pe_rsc_debug(rsc, "Dependency loop detected involving %s", rsc->id);
 100         return NULL;
 101     }
 102 
 103     if (group_data->first_child == NULL) {
 104         // Nothing to allocate
 105         pe__clear_resource_flags(rsc, pe_rsc_provisional);
 106         return NULL;
 107     }
 108 
 109     pe__set_resource_flags(rsc, pe_rsc_allocating);
 110     rsc->role = group_data->first_child->role;
 111 
 112     expand_group_colocations(rsc);
 113 
 114     pe__show_node_weights(!pcmk_is_set(data_set->flags, pe_flag_show_scores),
 115                           rsc, __func__, rsc->allowed_nodes, data_set);
 116 
 117     gIter = rsc->children;
 118     for (; gIter != NULL; gIter = gIter->next) {
 119         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 120 
 121         pe_rsc_trace(rsc, "Allocating group %s member %s",
 122                      rsc->id, child_rsc->id);
 123         node = child_rsc->cmds->allocate(child_rsc, prefer, data_set);
 124         if (group_node == NULL) {
 125             group_node = node;
 126         }
 127     }
 128 
 129     pe__set_next_role(rsc, group_data->first_child->next_role,
 130                       "first group member");
 131     pe__clear_resource_flags(rsc, pe_rsc_allocating|pe_rsc_provisional);
 132 
 133     if (group_data->colocated) {
 134         return group_node;
 135     }
 136     return NULL;
 137 }
 138 
 139 void group_update_pseudo_status(pe_resource_t * parent, pe_resource_t * child);
 140 
 141 void
 142 group_create_actions(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144     pe_action_t *op = NULL;
 145     const char *value = NULL;
 146     GList *gIter = rsc->children;
 147 
 148     pe_rsc_trace(rsc, "Creating actions for %s", rsc->id);
 149 
 150     for (; gIter != NULL; gIter = gIter->next) {
 151         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 152 
 153         child_rsc->cmds->create_actions(child_rsc, data_set);
 154         group_update_pseudo_status(rsc, child_rsc);
 155     }
 156 
 157     op = start_action(rsc, NULL, TRUE /* !group_data->child_starting */ );
 158     pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 159 
 160     op = custom_action(rsc, started_key(rsc),
 161                        RSC_STARTED, NULL, TRUE /* !group_data->child_starting */ , TRUE, data_set);
 162     pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 163 
 164     op = stop_action(rsc, NULL, TRUE /* !group_data->child_stopping */ );
 165     pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 166 
 167     op = custom_action(rsc, stopped_key(rsc),
 168                        RSC_STOPPED, NULL, TRUE /* !group_data->child_stopping */ , TRUE, data_set);
 169     pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 170 
 171     value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_PROMOTABLE);
 172     if (crm_is_true(value)) {
 173         op = custom_action(rsc, demote_key(rsc), RSC_DEMOTE, NULL, TRUE, TRUE, data_set);
 174         pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 175 
 176         op = custom_action(rsc, demoted_key(rsc), RSC_DEMOTED, NULL, TRUE, TRUE, data_set);
 177         pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 178 
 179         op = custom_action(rsc, promote_key(rsc), RSC_PROMOTE, NULL, TRUE, TRUE, data_set);
 180         pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 181 
 182         op = custom_action(rsc, promoted_key(rsc), RSC_PROMOTED, NULL, TRUE, TRUE, data_set);
 183         pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 184     }
 185 }
 186 
 187 void
 188 group_update_pseudo_status(pe_resource_t * parent, pe_resource_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190     GList *gIter = child->actions;
 191     group_variant_data_t *group_data = NULL;
 192 
 193     get_group_variant_data(group_data, parent);
 194 
 195     if (group_data->ordered == FALSE) {
 196         /* If this group is not ordered, then leave the meta-actions as optional */
 197         return;
 198     }
 199 
 200     if (group_data->child_stopping && group_data->child_starting) {
 201         return;
 202     }
 203 
 204     for (; gIter != NULL; gIter = gIter->next) {
 205         pe_action_t *action = (pe_action_t *) gIter->data;
 206 
 207         if (pcmk_is_set(action->flags, pe_action_optional)) {
 208             continue;
 209         }
 210         if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_casei)
 211             && pcmk_is_set(action->flags, pe_action_runnable)) {
 212 
 213             group_data->child_stopping = TRUE;
 214             pe_rsc_trace(action->rsc, "Based on %s the group is stopping", action->uuid);
 215 
 216         } else if (pcmk__str_eq(RSC_START, action->task, pcmk__str_casei)
 217                    && pcmk_is_set(action->flags, pe_action_runnable)) {
 218             group_data->child_starting = TRUE;
 219             pe_rsc_trace(action->rsc, "Based on %s the group is starting", action->uuid);
 220         }
 221     }
 222 }
 223 
 224 void
 225 group_internal_constraints(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227     GList *gIter = rsc->children;
 228     pe_resource_t *last_rsc = NULL;
 229     pe_resource_t *last_active = NULL;
 230     pe_resource_t *top = uber_parent(rsc);
 231     group_variant_data_t *group_data = NULL;
 232 
 233     get_group_variant_data(group_data, rsc);
 234 
 235     pcmk__order_resource_actions(rsc, RSC_STOPPED, rsc, RSC_START,
 236                                  pe_order_optional, data_set);
 237     pcmk__order_resource_actions(rsc, RSC_START, rsc, RSC_STARTED,
 238                                  pe_order_runnable_left, data_set);
 239     pcmk__order_resource_actions(rsc, RSC_STOP, rsc, RSC_STOPPED,
 240                                  pe_order_runnable_left, data_set);
 241 
 242     for (; gIter != NULL; gIter = gIter->next) {
 243         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 244         int stop = pe_order_none;
 245         int stopped = pe_order_implies_then_printed;
 246         int start = pe_order_implies_then | pe_order_runnable_left;
 247         int started =
 248             pe_order_runnable_left | pe_order_implies_then | pe_order_implies_then_printed;
 249 
 250         child_rsc->cmds->internal_constraints(child_rsc, data_set);
 251 
 252         if (last_rsc == NULL) {
 253             if (group_data->ordered) {
 254                 pe__set_order_flags(stop, pe_order_optional);
 255                 stopped = pe_order_implies_then;
 256             }
 257 
 258         } else if (group_data->colocated) {
 259             pcmk__new_colocation("group:internal_colocation", NULL, INFINITY,
 260                                  child_rsc, last_rsc, NULL, NULL,
 261                                  pcmk_is_set(child_rsc->flags, pe_rsc_critical),
 262                                  data_set);
 263         }
 264 
 265         if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
 266             pcmk__order_resource_actions(rsc, RSC_DEMOTE, child_rsc, RSC_DEMOTE,
 267                                          stop|pe_order_implies_first_printed,
 268                                          data_set);
 269 
 270             pcmk__order_resource_actions(child_rsc, RSC_DEMOTE, rsc,
 271                                          RSC_DEMOTED, stopped, data_set);
 272 
 273             pcmk__order_resource_actions(child_rsc, RSC_PROMOTE, rsc,
 274                                          RSC_PROMOTED, started, data_set);
 275 
 276             pcmk__order_resource_actions(rsc, RSC_PROMOTE, child_rsc,
 277                                          RSC_PROMOTE,
 278                                          pe_order_implies_first_printed,
 279                                          data_set);
 280 
 281         }
 282 
 283         pcmk__order_starts(rsc, child_rsc, pe_order_implies_first_printed,
 284                            data_set);
 285         pcmk__order_stops(rsc, child_rsc,
 286                           stop|pe_order_implies_first_printed, data_set);
 287 
 288         pcmk__order_resource_actions(child_rsc, RSC_STOP, rsc, RSC_STOPPED,
 289                                      stopped, data_set);
 290         pcmk__order_resource_actions(child_rsc, RSC_START, rsc, RSC_STARTED,
 291                                      started, data_set);
 292 
 293         if (group_data->ordered == FALSE) {
 294             pcmk__order_starts(rsc, child_rsc,
 295                                start|pe_order_implies_first_printed, data_set);
 296             if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
 297                 pcmk__order_resource_actions(rsc, RSC_PROMOTE, child_rsc,
 298                                              RSC_PROMOTE,
 299                                              start|pe_order_implies_first_printed,
 300                                              data_set);
 301             }
 302 
 303         } else if (last_rsc != NULL) {
 304             pcmk__order_starts(last_rsc, child_rsc, start, data_set);
 305             pcmk__order_stops(child_rsc, last_rsc,
 306                               pe_order_optional|pe_order_restart, data_set);
 307 
 308             if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
 309                 pcmk__order_resource_actions(last_rsc, RSC_PROMOTE, child_rsc,
 310                                              RSC_PROMOTE, start, data_set);
 311                 pcmk__order_resource_actions(child_rsc, RSC_DEMOTE, last_rsc,
 312                                              RSC_DEMOTE, pe_order_optional,
 313                                              data_set);
 314             }
 315 
 316         } else {
 317             pcmk__order_starts(rsc, child_rsc, pe_order_none, data_set);
 318             if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
 319                 pcmk__order_resource_actions(rsc, RSC_PROMOTE, child_rsc,
 320                                              RSC_PROMOTE, pe_order_none,
 321                                              data_set);
 322             }
 323         }
 324 
 325         /* Look for partially active groups
 326          * Make sure they still shut down in sequence
 327          */
 328         if (child_rsc->running_on) {
 329             if (group_data->ordered
 330                 && last_rsc
 331                 && last_rsc->running_on == NULL && last_active && last_active->running_on) {
 332                 pcmk__order_stops(child_rsc, last_active, pe_order_optional,
 333                                   data_set);
 334             }
 335             last_active = child_rsc;
 336         }
 337 
 338         last_rsc = child_rsc;
 339     }
 340 
 341     if (group_data->ordered && last_rsc != NULL) {
 342         int stop_stop_flags = pe_order_implies_then;
 343         int stop_stopped_flags = pe_order_optional;
 344 
 345         pcmk__order_stops(rsc, last_rsc, stop_stop_flags, data_set);
 346         pcmk__order_resource_actions(last_rsc, RSC_STOP, rsc, RSC_STOPPED,
 347                                      stop_stopped_flags, data_set);
 348 
 349         if (pcmk_is_set(top->flags, pe_rsc_promotable)) {
 350             pcmk__order_resource_actions(rsc, RSC_DEMOTE, last_rsc, RSC_DEMOTE,
 351                                          stop_stop_flags, data_set);
 352             pcmk__order_resource_actions(last_rsc, RSC_DEMOTE, rsc, RSC_DEMOTED,
 353                                          stop_stopped_flags, data_set);
 354         }
 355     }
 356 }
 357 
 358 void
 359 group_rsc_colocation_lh(pe_resource_t *dependent, pe_resource_t *primary,
     /* [previous][next][first][last][top][bottom][index][help] */
 360                         pcmk__colocation_t *constraint,
 361                         pe_working_set_t *data_set)
 362 {
 363     GList *gIter = NULL;
 364     group_variant_data_t *group_data = NULL;
 365 
 366     if (dependent == NULL) {
 367         pe_err("dependent was NULL for %s", constraint->id);
 368         return;
 369 
 370     } else if (primary == NULL) {
 371         pe_err("primary was NULL for %s", constraint->id);
 372         return;
 373     }
 374 
 375     gIter = dependent->children;
 376     pe_rsc_trace(dependent, "Processing constraints from %s", dependent->id);
 377 
 378     get_group_variant_data(group_data, dependent);
 379 
 380     if (group_data->colocated) {
 381         group_data->first_child->cmds->rsc_colocation_lh(group_data->first_child,
 382                                                          primary, constraint,
 383                                                          data_set);
 384         return;
 385 
 386     } else if (constraint->score >= INFINITY) {
 387         pcmk__config_err("%s: Cannot perform mandatory colocation "
 388                          "between non-colocated group and %s",
 389                          dependent->id, primary->id);
 390         return;
 391     }
 392 
 393     for (; gIter != NULL; gIter = gIter->next) {
 394         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 395 
 396         child_rsc->cmds->rsc_colocation_lh(child_rsc, primary, constraint,
 397                                            data_set);
 398     }
 399 }
 400 
 401 void
 402 group_rsc_colocation_rh(pe_resource_t *dependent, pe_resource_t *primary,
     /* [previous][next][first][last][top][bottom][index][help] */
 403                         pcmk__colocation_t *constraint,
 404                         pe_working_set_t *data_set)
 405 {
 406     GList *gIter = primary->children;
 407     group_variant_data_t *group_data = NULL;
 408 
 409     get_group_variant_data(group_data, primary);
 410     CRM_CHECK(dependent->variant == pe_native, return);
 411 
 412     pe_rsc_trace(primary, "Processing RH %s of constraint %s (LH is %s)",
 413                  primary->id, constraint->id, dependent->id);
 414 
 415     if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
 416         return;
 417 
 418     } else if (group_data->colocated && group_data->first_child) {
 419         if (constraint->score >= INFINITY) {
 420             /* Ensure RHS is _fully_ up before can start LHS */
 421             group_data->last_child->cmds->rsc_colocation_rh(dependent,
 422                                                             group_data->last_child,
 423                                                             constraint,
 424                                                             data_set);
 425         } else {
 426             /* A partially active RHS is fine */
 427             group_data->first_child->cmds->rsc_colocation_rh(dependent,
 428                                                              group_data->first_child,
 429                                                              constraint,
 430                                                              data_set);
 431         }
 432 
 433         return;
 434 
 435     } else if (constraint->score >= INFINITY) {
 436         pcmk__config_err("%s: Cannot perform mandatory colocation with"
 437                          " non-colocated group %s", dependent->id, primary->id);
 438         return;
 439     }
 440 
 441     for (; gIter != NULL; gIter = gIter->next) {
 442         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 443 
 444         child_rsc->cmds->rsc_colocation_rh(dependent, child_rsc, constraint,
 445                                            data_set);
 446     }
 447 }
 448 
 449 enum pe_action_flags
 450 group_action_flags(pe_action_t * action, pe_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
 451 {
 452     GList *gIter = NULL;
 453     enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
 454 
 455     for (gIter = action->rsc->children; gIter != NULL; gIter = gIter->next) {
 456         pe_resource_t *child = (pe_resource_t *) gIter->data;
 457         enum action_tasks task = get_complex_task(child, action->task, TRUE);
 458         const char *task_s = task2text(task);
 459         pe_action_t *child_action = find_first_action(child->actions, NULL, task_s, node);
 460 
 461         if (child_action) {
 462             enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);
 463 
 464             if (pcmk_is_set(flags, pe_action_optional)
 465                 && !pcmk_is_set(child_flags, pe_action_optional)) {
 466                 pe_rsc_trace(action->rsc, "%s is mandatory because of %s", action->uuid,
 467                              child_action->uuid);
 468                 pe__clear_raw_action_flags(flags, "group action",
 469                                            pe_action_optional);
 470                 pe__clear_action_flags(action, pe_action_optional);
 471             }
 472             if (!pcmk__str_eq(task_s, action->task, pcmk__str_casei)
 473                 && pcmk_is_set(flags, pe_action_runnable)
 474                 && !pcmk_is_set(child_flags, pe_action_runnable)) {
 475 
 476                 pe_rsc_trace(action->rsc, "%s is not runnable because of %s", action->uuid,
 477                              child_action->uuid);
 478                 pe__clear_raw_action_flags(flags, "group action",
 479                                            pe_action_runnable);
 480                 pe__clear_action_flags(action, pe_action_runnable);
 481             }
 482 
 483         } else if (task != stop_rsc && task != action_demote) {
 484             pe_rsc_trace(action->rsc, "%s is not runnable because of %s (not found in %s)",
 485                          action->uuid, task_s, child->id);
 486             pe__clear_raw_action_flags(flags, "group action",
 487                                        pe_action_runnable);
 488         }
 489     }
 490 
 491     return flags;
 492 }
 493 
 494 enum pe_graph_flags
 495 group_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
 496                      enum pe_action_flags flags, enum pe_action_flags filter,
 497                      enum pe_ordering type, pe_working_set_t *data_set)
 498 {
 499     GList *gIter = then->rsc->children;
 500     enum pe_graph_flags changed = pe_graph_none;
 501 
 502     CRM_ASSERT(then->rsc != NULL);
 503     changed |= native_update_actions(first, then, node, flags, filter, type,
 504                                      data_set);
 505 
 506     for (; gIter != NULL; gIter = gIter->next) {
 507         pe_resource_t *child = (pe_resource_t *) gIter->data;
 508         pe_action_t *child_action = find_first_action(child->actions, NULL, then->task, node);
 509 
 510         if (child_action) {
 511             changed |= child->cmds->update_actions(first, child_action, node,
 512                                                    flags, filter, type,
 513                                                    data_set);
 514         }
 515     }
 516 
 517     return changed;
 518 }
 519 
 520 void
 521 group_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {
 523     GList *gIter = rsc->children;
 524     GList *saved = constraint->node_list_rh;
 525     GList *zero = pcmk__copy_node_list(constraint->node_list_rh, true);
 526     gboolean reset_scores = TRUE;
 527     group_variant_data_t *group_data = NULL;
 528 
 529     get_group_variant_data(group_data, rsc);
 530 
 531     pe_rsc_debug(rsc, "Processing rsc_location %s for %s", constraint->id, rsc->id);
 532 
 533     pcmk__apply_location(constraint, rsc);
 534 
 535     for (; gIter != NULL; gIter = gIter->next) {
 536         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 537 
 538         child_rsc->cmds->rsc_location(child_rsc, constraint);
 539         if (group_data->colocated && reset_scores) {
 540             reset_scores = FALSE;
 541             constraint->node_list_rh = zero;
 542         }
 543     }
 544 
 545     constraint->node_list_rh = saved;
 546     g_list_free_full(zero, free);
 547 }
 548 
 549 void
 550 group_expand(pe_resource_t * rsc, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 551 {
 552     CRM_CHECK(rsc != NULL, return);
 553 
 554     pe_rsc_trace(rsc, "Processing actions from %s", rsc->id);
 555     native_expand(rsc, data_set);
 556 
 557     for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 558         pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
 559 
 560         child_rsc->cmds->expand(child_rsc, data_set);
 561     }
 562 }
 563 
 564 GHashTable *
 565 pcmk__group_merge_weights(pe_resource_t *rsc, const char *primary_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 566                           GHashTable *nodes, const char *attr, float factor,
 567                           uint32_t flags)
 568 {
 569     GList *gIter = rsc->rsc_cons_lhs;
 570     group_variant_data_t *group_data = NULL;
 571 
 572     get_group_variant_data(group_data, rsc);
 573 
 574     if (pcmk_is_set(rsc->flags, pe_rsc_merging)) {
 575         pe_rsc_info(rsc, "Breaking dependency loop with %s at %s",
 576                     rsc->id, primary_id);
 577         return nodes;
 578     }
 579 
 580     pe__set_resource_flags(rsc, pe_rsc_merging);
 581 
 582     nodes = group_data->first_child->cmds->merge_weights(group_data->first_child,
 583                                                          primary_id, nodes,
 584                                                          attr, factor, flags);
 585 
 586     for (; gIter != NULL; gIter = gIter->next) {
 587         pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
 588 
 589         nodes = pcmk__native_merge_weights(constraint->dependent, rsc->id,
 590                                            nodes, constraint->node_attribute,
 591                                            constraint->score / (float) INFINITY,
 592                                            flags);
 593     }
 594 
 595     pe__clear_resource_flags(rsc, pe_rsc_merging);
 596     return nodes;
 597 }
 598 
 599 void
 600 group_append_meta(pe_resource_t * rsc, xmlNode * xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 601 {
 602 }
 603 
 604 // Group implementation of resource_alloc_functions_t:colocated_resources()
 605 GList *
 606 pcmk__group_colocated_resources(pe_resource_t *rsc, pe_resource_t *orig_rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 607                                 GList *colocated_rscs)
 608 {
 609     pe_resource_t *child_rsc = NULL;
 610     group_variant_data_t *group_data = NULL;
 611 
 612     get_group_variant_data(group_data, rsc);
 613 
 614     if (orig_rsc == NULL) {
 615         orig_rsc = rsc;
 616     }
 617 
 618     if (group_data->colocated || pe_rsc_is_clone(rsc->parent)) {
 619         /* This group has colocated members and/or is cloned -- either way,
 620          * add every child's colocated resources to the list.
 621          */
 622         for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 623             child_rsc = (pe_resource_t *) gIter->data;
 624             colocated_rscs = child_rsc->cmds->colocated_resources(child_rsc,
 625                                                                   orig_rsc,
 626                                                                   colocated_rscs);
 627         }
 628 
 629     } else if (group_data->first_child != NULL) {
 630         /* This group's members are not colocated, and the group is not cloned,
 631          * so just add the first child's colocations to the list.
 632          */
 633         child_rsc = group_data->first_child;
 634         colocated_rscs = child_rsc->cmds->colocated_resources(child_rsc,
 635                                                               orig_rsc,
 636                                                               colocated_rscs);
 637     }
 638 
 639     // Now consider colocations where the group itself is specified
 640     colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc, colocated_rscs);
 641 
 642     return colocated_rscs;
 643 }
 644 
 645 // Group implementation of resource_alloc_functions_t:add_utilization()
 646 void
 647 pcmk__group_add_utilization(pe_resource_t *rsc, pe_resource_t *orig_rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 648                             GList *all_rscs, GHashTable *utilization)
 649 {
 650     group_variant_data_t *group_data = NULL;
 651     pe_resource_t *child = NULL;
 652 
 653     if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
 654         return;
 655     }
 656 
 657     pe_rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
 658                  orig_rsc->id, rsc->id);
 659     get_group_variant_data(group_data, rsc);
 660     if (group_data->colocated || pe_rsc_is_clone(rsc->parent)) {
 661         // Every group member will be on same node, so sum all members
 662         for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 663             child = (pe_resource_t *) iter->data;
 664 
 665             if (pcmk_is_set(child->flags, pe_rsc_provisional)
 666                 && (g_list_find(all_rscs, child) == NULL)) {
 667                 child->cmds->add_utilization(child, orig_rsc, all_rscs,
 668                                              utilization);
 669             }
 670         }
 671 
 672     } else {
 673         // Just add first child's utilization
 674         child = group_data->first_child;
 675         if ((child != NULL)
 676             && pcmk_is_set(child->flags, pe_rsc_provisional)
 677             && (g_list_find(all_rscs, child) == NULL)) {
 678 
 679             child->cmds->add_utilization(child, orig_rsc, all_rscs,
 680                                          utilization);
 681         }
 682     }
 683 }
 684 
 685 // Group implementation of resource_alloc_functions_t:shutdown_lock()
 686 void
 687 pcmk__group_shutdown_lock(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 688 {
 689     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 690         pe_resource_t *child = (pe_resource_t *) iter->data;
 691 
 692         child->cmds->shutdown_lock(child);
 693     }
 694 }

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