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

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

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