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_assign
  3. create_group_pseudo_op
  4. pcmk__group_create_actions
  5. member_internal_constraints
  6. pcmk__group_internal_constraints
  7. colocate_group_with
  8. colocate_with_group
  9. pcmk__group_apply_coloc_score
  10. pcmk__group_action_flags
  11. pcmk__group_update_ordered_actions
  12. pcmk__group_apply_location
  13. pcmk__group_colocated_resources
  14. pcmk__group_add_utilization
  15. pcmk__group_shutdown_lock

   1 /*
   2  * Copyright 2004-2022 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 #include "libpacemaker_private.h"
  18 
  19 /*!
  20  * \internal
  21  * \brief Expand a group's colocations to its members
  22  *
  23  * \param[in,out] rsc  Group resource
  24  */
  25 static void
  26 expand_group_colocations(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     pe_resource_t *member = NULL;
  29     bool any_unmanaged = false;
  30     GList *item = NULL;
  31 
  32     if (rsc->children == NULL) {
  33         return;
  34     }
  35 
  36     // Treat "group with R" colocations as "first member with R"
  37     member = (pe_resource_t *) rsc->children->data;
  38     for (item = rsc->rsc_cons; item != NULL; item = item->next) {
  39         pcmk__add_this_with(member, (pcmk__colocation_t *) (item->data));
  40     }
  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_colocation_dependents() will ensure that dependent resources
  49      * in 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 (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                     pcmk__add_this_with(member, constraint);
  68                 }
  69             }
  70         } else if (!pcmk_is_set(member->flags, pe_rsc_managed)) {
  71             any_unmanaged = true;
  72         }
  73     }
  74 
  75     g_list_free(rsc->rsc_cons);
  76     rsc->rsc_cons = NULL;
  77 
  78     // Treat "R with group" colocations as "R with last member"
  79     member = pe__last_group_member(rsc);
  80     for (item = rsc->rsc_cons_lhs; item != NULL; item = item->next) {
  81         pcmk__add_with_this(member, (pcmk__colocation_t *) (item->data));
  82     }
  83     g_list_free(rsc->rsc_cons_lhs);
  84     rsc->rsc_cons_lhs = NULL;
  85 }
  86 
  87 /*!
  88  * \internal
  89  * \brief Assign a group resource to a node
  90  *
  91  * \param[in,out] rsc     Group resource to assign to a node
  92  * \param[in]     prefer  Node to prefer, if all else is equal
  93  *
  94  * \return Node that \p rsc is assigned to, if assigned entirely to one node
  95  */
  96 pe_node_t *
  97 pcmk__group_assign(pe_resource_t *rsc, const pe_node_t *prefer)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99     pe_node_t *first_assigned_node = NULL;
 100     pe_resource_t *first_member = NULL;
 101 
 102     CRM_ASSERT(rsc != NULL);
 103 
 104     if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
 105         return rsc->allocated_to; // Assignment already done
 106     }
 107     if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) {
 108         pe_rsc_debug(rsc, "Assignment dependency loop detected involving %s",
 109                      rsc->id);
 110         return NULL;
 111     }
 112 
 113     if (rsc->children == NULL) {
 114         // No members to assign
 115         pe__clear_resource_flags(rsc, pe_rsc_provisional);
 116         return NULL;
 117     }
 118 
 119     pe__set_resource_flags(rsc, pe_rsc_allocating);
 120     first_member = (pe_resource_t *) rsc->children->data;
 121     rsc->role = first_member->role;
 122 
 123     expand_group_colocations(rsc);
 124 
 125     pe__show_node_weights(!pcmk_is_set(rsc->cluster->flags, pe_flag_show_scores),
 126                           rsc, __func__, rsc->allowed_nodes, rsc->cluster);
 127 
 128     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 129         pe_resource_t *member = (pe_resource_t *) iter->data;
 130         pe_node_t *node = NULL;
 131 
 132         pe_rsc_trace(rsc, "Assigning group %s member %s",
 133                      rsc->id, member->id);
 134         node = member->cmds->assign(member, prefer);
 135         if (first_assigned_node == NULL) {
 136             first_assigned_node = node;
 137         }
 138     }
 139 
 140     pe__set_next_role(rsc, first_member->next_role, "first group member");
 141     pe__clear_resource_flags(rsc, pe_rsc_allocating|pe_rsc_provisional);
 142 
 143     if (!pe__group_flag_is_set(rsc, pe__group_colocated)) {
 144         return NULL;
 145     }
 146     return first_assigned_node;
 147 }
 148 
 149 /*!
 150  * \internal
 151  * \brief Create a pseudo-operation for a group as an ordering point
 152  *
 153  * \param[in,out] group   Group resource to create action for
 154  * \param[in]     action  Action name
 155  *
 156  * \return Newly created pseudo-operation
 157  */
 158 static pe_action_t *
 159 create_group_pseudo_op(pe_resource_t *group, const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161     pe_action_t *op = custom_action(group, pcmk__op_key(group->id, action, 0),
 162                                     action, NULL, TRUE, TRUE, group->cluster);
 163     pe__set_action_flags(op, pe_action_pseudo|pe_action_runnable);
 164     return op;
 165 }
 166 
 167 /*!
 168  * \internal
 169  * \brief Create all actions needed for a given group resource
 170  *
 171  * \param[in,out] rsc  Group resource to create actions for
 172  */
 173 void
 174 pcmk__group_create_actions(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 175 {
 176     CRM_ASSERT(rsc != NULL);
 177 
 178     pe_rsc_trace(rsc, "Creating actions for group %s", rsc->id);
 179 
 180     // Create actions for individual group members
 181     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 182         pe_resource_t *member = (pe_resource_t *) iter->data;
 183 
 184         member->cmds->create_actions(member);
 185     }
 186 
 187     // Create pseudo-actions for group itself to serve as ordering points
 188     create_group_pseudo_op(rsc, RSC_START);
 189     create_group_pseudo_op(rsc, RSC_STARTED);
 190     create_group_pseudo_op(rsc, RSC_STOP);
 191     create_group_pseudo_op(rsc, RSC_STOPPED);
 192     if (crm_is_true(g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_PROMOTABLE))) {
 193         create_group_pseudo_op(rsc, RSC_DEMOTE);
 194         create_group_pseudo_op(rsc, RSC_DEMOTED);
 195         create_group_pseudo_op(rsc, RSC_PROMOTE);
 196         create_group_pseudo_op(rsc, RSC_PROMOTED);
 197     }
 198 }
 199 
 200 // User data for member_internal_constraints()
 201 struct member_data {
 202     // These could be derived from member but this avoids some function calls
 203     bool ordered;
 204     bool colocated;
 205     bool promotable;
 206 
 207     pe_resource_t *last_active;
 208     pe_resource_t *previous_member;
 209 };
 210 
 211 /*!
 212  * \internal
 213  * \brief Create implicit constraints needed for a group member
 214  *
 215  * \param[in,out] data       Group member to create implicit constraints for
 216  * \param[in,out] user_data  Group member to create implicit constraints for
 217  */
 218 static void
 219 member_internal_constraints(gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221     pe_resource_t *member = (pe_resource_t *) data;
 222     struct member_data *member_data = (struct member_data *) user_data;
 223 
 224     // For ordering demote vs demote or stop vs stop
 225     uint32_t down_flags = pe_order_implies_first_printed;
 226 
 227     // For ordering demote vs demoted or stop vs stopped
 228     uint32_t post_down_flags = pe_order_implies_then_printed;
 229 
 230     // Create the individual member's implicit constraints
 231     member->cmds->internal_constraints(member);
 232 
 233     if (member_data->previous_member == NULL) {
 234         // This is first member
 235         if (member_data->ordered) {
 236             pe__set_order_flags(down_flags, pe_order_optional);
 237             post_down_flags = pe_order_implies_then;
 238         }
 239 
 240     } else if (member_data->colocated) {
 241         // Colocate this member with the previous one
 242         pcmk__new_colocation("group:internal_colocation", NULL, INFINITY,
 243                              member, member_data->previous_member, NULL, NULL,
 244                              pcmk_is_set(member->flags, pe_rsc_critical),
 245                              member->cluster);
 246     }
 247 
 248     if (member_data->promotable) {
 249         // Demote group -> demote member -> group is demoted
 250         pcmk__order_resource_actions(member->parent, RSC_DEMOTE,
 251                                      member, RSC_DEMOTE, down_flags);
 252         pcmk__order_resource_actions(member, RSC_DEMOTE,
 253                                      member->parent, RSC_DEMOTED,
 254                                      post_down_flags);
 255 
 256         // Promote group -> promote member -> group is promoted
 257         pcmk__order_resource_actions(member, RSC_PROMOTE,
 258                                      member->parent, RSC_PROMOTED,
 259                                      pe_order_runnable_left
 260                                      |pe_order_implies_then
 261                                      |pe_order_implies_then_printed);
 262         pcmk__order_resource_actions(member->parent, RSC_PROMOTE,
 263                                      member, RSC_PROMOTE,
 264                                      pe_order_implies_first_printed);
 265     }
 266 
 267     // Stop group -> stop member -> group is stopped
 268     pcmk__order_stops(member->parent, member, down_flags);
 269     pcmk__order_resource_actions(member, RSC_STOP, member->parent, RSC_STOPPED,
 270                                  post_down_flags);
 271 
 272     // Start group -> start member -> group is started
 273     pcmk__order_starts(member->parent, member, pe_order_implies_first_printed);
 274     pcmk__order_resource_actions(member, RSC_START, member->parent, RSC_STARTED,
 275                                  pe_order_runnable_left
 276                                  |pe_order_implies_then
 277                                  |pe_order_implies_then_printed);
 278 
 279     if (!member_data->ordered) {
 280         pcmk__order_starts(member->parent, member,
 281                            pe_order_implies_then
 282                            |pe_order_runnable_left
 283                            |pe_order_implies_first_printed);
 284         if (member_data->promotable) {
 285             pcmk__order_resource_actions(member->parent, RSC_PROMOTE, member,
 286                                          RSC_PROMOTE,
 287                                          pe_order_implies_then
 288                                          |pe_order_runnable_left
 289                                          |pe_order_implies_first_printed);
 290         }
 291 
 292     } else if (member_data->previous_member == NULL) {
 293         pcmk__order_starts(member->parent, member, pe_order_none);
 294         if (member_data->promotable) {
 295             pcmk__order_resource_actions(member->parent, RSC_PROMOTE, member,
 296                                          RSC_PROMOTE, pe_order_none);
 297         }
 298 
 299     } else {
 300         // Order this member relative to the previous one
 301         pcmk__order_starts(member_data->previous_member, member,
 302                            pe_order_implies_then|pe_order_runnable_left);
 303         pcmk__order_stops(member, member_data->previous_member,
 304                           pe_order_optional|pe_order_restart);
 305         if (member_data->promotable) {
 306             pcmk__order_resource_actions(member_data->previous_member,
 307                                          RSC_PROMOTE, member, RSC_PROMOTE,
 308                                          pe_order_implies_then
 309                                          |pe_order_runnable_left);
 310             pcmk__order_resource_actions(member, RSC_DEMOTE,
 311                                          member_data->previous_member,
 312                                          RSC_DEMOTE, pe_order_optional);
 313         }
 314     }
 315 
 316     // Make sure partially active groups shut down in sequence
 317     if (member->running_on != NULL) {
 318         if (member_data->ordered && (member_data->previous_member != NULL)
 319             && (member_data->previous_member->running_on == NULL)
 320             && (member_data->last_active != NULL)
 321             && (member_data->last_active->running_on != NULL)) {
 322             pcmk__order_stops(member, member_data->last_active, pe_order_optional);
 323         }
 324         member_data->last_active = member;
 325     }
 326 
 327     member_data->previous_member = member;
 328 }
 329 
 330 /*!
 331  * \internal
 332  * \brief Create implicit constraints needed for a group resource
 333  *
 334  * \param[in,out] rsc  Group resource to create implicit constraints for
 335  */
 336 void
 337 pcmk__group_internal_constraints(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 338 {
 339     struct member_data member_data = { false, };
 340 
 341     CRM_ASSERT(rsc != NULL);
 342 
 343     /* Order group pseudo-actions relative to each other for restarting:
 344      * stop group -> group is stopped -> start group -> group is started
 345      */
 346     pcmk__order_resource_actions(rsc, RSC_STOP, rsc, RSC_STOPPED,
 347                                  pe_order_runnable_left);
 348     pcmk__order_resource_actions(rsc, RSC_STOPPED, rsc, RSC_START,
 349                                  pe_order_optional);
 350     pcmk__order_resource_actions(rsc, RSC_START, rsc, RSC_STARTED,
 351                                  pe_order_runnable_left);
 352 
 353     member_data.ordered = pe__group_flag_is_set(rsc, pe__group_ordered);
 354     member_data.colocated = pe__group_flag_is_set(rsc, pe__group_colocated);
 355     member_data.promotable = pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable);
 356     g_list_foreach(rsc->children, member_internal_constraints, &member_data);
 357 }
 358 
 359 /*!
 360  * \internal
 361  * \brief Apply a colocation's score to node weights or resource priority
 362  *
 363  * Given a colocation constraint for a group with some other resource, apply the
 364  * score to the dependent's allowed node weights (if we are still placing
 365  * resources) or priority (if we are choosing promotable clone instance roles).
 366  *
 367  * \param[in,out] dependent      Dependent group resource in colocation
 368  * \param[in]     primary        Primary resource in colocation
 369  * \param[in]     colocation     Colocation constraint to apply
 370  */
 371 static void
 372 colocate_group_with(pe_resource_t *dependent, const pe_resource_t *primary,
     /* [previous][next][first][last][top][bottom][index][help] */
 373                     const pcmk__colocation_t *colocation)
 374 {
 375     pe_resource_t *member = NULL;
 376 
 377     if (dependent->children == NULL) {
 378         return;
 379     }
 380 
 381     pe_rsc_trace(primary, "Processing %s (group %s with %s) for dependent",
 382                  colocation->id, dependent->id, primary->id);
 383 
 384     if (pe__group_flag_is_set(dependent, pe__group_colocated)) {
 385         // Colocate first member (internal colocations will handle the rest)
 386         member = (pe_resource_t *) dependent->children->data;
 387         member->cmds->apply_coloc_score(member, primary, colocation, true);
 388         return;
 389     }
 390 
 391     if (colocation->score >= INFINITY) {
 392         pcmk__config_err("%s: Cannot perform mandatory colocation between "
 393                          "non-colocated group and %s",
 394                          dependent->id, primary->id);
 395         return;
 396     }
 397 
 398     // Colocate each member individually
 399     for (GList *iter = dependent->children; iter != NULL; iter = iter->next) {
 400         member = (pe_resource_t *) iter->data;
 401         member->cmds->apply_coloc_score(member, primary, colocation, true);
 402     }
 403 }
 404 
 405 /*!
 406  * \internal
 407  * \brief Apply a colocation's score to node weights or resource priority
 408  *
 409  * Given a colocation constraint for some other resource with a group, apply the
 410  * score to the dependent's allowed node weights (if we are still placing
 411  * resources) or priority (if we are choosing promotable clone instance roles).
 412  *
 413  * \param[in,out] dependent      Dependent resource in colocation
 414  * \param[in]     primary        Primary group resource in colocation
 415  * \param[in]     colocation     Colocation constraint to apply
 416  */
 417 static void
 418 colocate_with_group(pe_resource_t *dependent, const pe_resource_t *primary,
     /* [previous][next][first][last][top][bottom][index][help] */
 419                     const pcmk__colocation_t *colocation)
 420 {
 421     pe_resource_t *member = NULL;
 422 
 423     pe_rsc_trace(primary,
 424                  "Processing colocation %s (%s with group %s) for primary",
 425                  colocation->id, dependent->id, primary->id);
 426 
 427     if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
 428         return;
 429     }
 430 
 431     if (pe__group_flag_is_set(primary, pe__group_colocated)) {
 432 
 433         if (colocation->score >= INFINITY) {
 434             /* For mandatory colocations, the entire group must be assignable
 435              * (and in the specified role if any), so apply the colocation based
 436              * on the last member.
 437              */
 438             member = pe__last_group_member(primary);
 439         } else if (primary->children != NULL) {
 440             /* For optional colocations, whether the group is partially or fully
 441              * up doesn't matter, so apply the colocation based on the first
 442              * member.
 443              */
 444             member = (pe_resource_t *) primary->children->data;
 445         }
 446         if (member == NULL) {
 447             return; // Nothing to colocate with
 448         }
 449 
 450         member->cmds->apply_coloc_score(dependent, member, colocation, false);
 451         return;
 452     }
 453 
 454     if (colocation->score >= INFINITY) {
 455         pcmk__config_err("%s: Cannot perform mandatory colocation with"
 456                          " non-colocated group %s",
 457                          dependent->id, primary->id);
 458         return;
 459     }
 460 
 461     // Colocate dependent with each member individually
 462     for (GList *iter = primary->children; iter != NULL; iter = iter->next) {
 463         member = (pe_resource_t *) iter->data;
 464         member->cmds->apply_coloc_score(dependent, member, colocation, false);
 465     }
 466 }
 467 
 468 /*!
 469  * \internal
 470  * \brief Apply a colocation's score to node weights or resource priority
 471  *
 472  * Given a colocation constraint, apply its score to the dependent's
 473  * allowed node weights (if we are still placing resources) or priority (if
 474  * we are choosing promotable clone instance roles).
 475  *
 476  * \param[in,out] dependent      Dependent resource in colocation
 477  * \param[in]     primary        Primary resource in colocation
 478  * \param[in]     colocation     Colocation constraint to apply
 479  * \param[in]     for_dependent  true if called on behalf of dependent
 480  */
 481 void
 482 pcmk__group_apply_coloc_score(pe_resource_t *dependent,
     /* [previous][next][first][last][top][bottom][index][help] */
 483                               const pe_resource_t *primary,
 484                               const pcmk__colocation_t *colocation,
 485                               bool for_dependent)
 486 {
 487     CRM_ASSERT((dependent != NULL) && (primary != NULL)
 488                && (colocation != NULL));
 489 
 490     if (for_dependent) {
 491         colocate_group_with(dependent, primary, colocation);
 492 
 493     } else {
 494         // Method should only be called for primitive dependents
 495         CRM_ASSERT(dependent->variant == pe_native);
 496 
 497         colocate_with_group(dependent, primary, colocation);
 498     }
 499 }
 500 
 501 /*!
 502  * \internal
 503  * \brief Return action flags for a given group resource action
 504  *
 505  * \param[in,out] action  Group action to get flags for
 506  * \param[in]     node    If not NULL, limit effects to this node
 507  *
 508  * \return Flags appropriate to \p action on \p node
 509  */
 510 enum pe_action_flags
 511 pcmk__group_action_flags(pe_action_t *action, const pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 512 {
 513     // Default flags for a group action
 514     enum pe_action_flags flags = pe_action_optional
 515                                  |pe_action_runnable
 516                                  |pe_action_pseudo;
 517 
 518     CRM_ASSERT(action != NULL);
 519 
 520     // Update flags considering each member's own flags for same action
 521     for (GList *iter = action->rsc->children; iter != NULL; iter = iter->next) {
 522         pe_resource_t *member = (pe_resource_t *) iter->data;
 523 
 524         // Check whether member has the same action
 525         enum action_tasks task = get_complex_task(member, action->task, TRUE);
 526         const char *task_s = task2text(task);
 527         pe_action_t *member_action = find_first_action(member->actions, NULL,
 528                                                        task_s, node);
 529 
 530         if (member_action != NULL) {
 531             enum pe_action_flags member_flags;
 532 
 533             member_flags = member->cmds->action_flags(member_action, node);
 534 
 535             // Group action is mandatory if any member action is
 536             if (pcmk_is_set(flags, pe_action_optional)
 537                 && !pcmk_is_set(member_flags, pe_action_optional)) {
 538                 pe_rsc_trace(action->rsc, "%s is mandatory because %s is",
 539                              action->uuid, member_action->uuid);
 540                 pe__clear_raw_action_flags(flags, "group action",
 541                                            pe_action_optional);
 542                 pe__clear_action_flags(action, pe_action_optional);
 543             }
 544 
 545             // Group action is unrunnable if any member action is
 546             if (!pcmk__str_eq(task_s, action->task, pcmk__str_none)
 547                 && pcmk_is_set(flags, pe_action_runnable)
 548                 && !pcmk_is_set(member_flags, pe_action_runnable)) {
 549 
 550                 pe_rsc_trace(action->rsc, "%s is unrunnable because %s is",
 551                              action->uuid, member_action->uuid);
 552                 pe__clear_raw_action_flags(flags, "group action",
 553                                            pe_action_runnable);
 554                 pe__clear_action_flags(action, pe_action_runnable);
 555             }
 556 
 557         /* Group (pseudo-)actions other than stop or demote are unrunnable
 558          * unless every member will do it.
 559          */
 560         } else if ((task != stop_rsc) && (task != action_demote)) {
 561             pe_rsc_trace(action->rsc,
 562                          "%s is not runnable because %s will not %s",
 563                          action->uuid, member->id, task_s);
 564             pe__clear_raw_action_flags(flags, "group action",
 565                                        pe_action_runnable);
 566         }
 567     }
 568 
 569     return flags;
 570 }
 571 
 572 /*!
 573  * \internal
 574  * \brief Update two actions according to an ordering between them
 575  *
 576  * Given information about an ordering of two actions, update the actions'
 577  * flags (and runnable_before members if appropriate) as appropriate for the
 578  * ordering. In some cases, the ordering could be disabled as well.
 579  *
 580  * \param[in,out] first     'First' action in an ordering
 581  * \param[in,out] then      'Then' action in an ordering
 582  * \param[in]     node      If not NULL, limit scope of ordering to this node
 583  *                          (only used when interleaving instances)
 584  * \param[in]     flags     Action flags for \p first for ordering purposes
 585  * \param[in]     filter    Action flags to limit scope of certain updates (may
 586  *                          include pe_action_optional to affect only mandatory
 587  *                          actions, and pe_action_runnable to affect only
 588  *                          runnable actions)
 589  * \param[in]     type      Group of enum pe_ordering flags to apply
 590  * \param[in,out] data_set  Cluster working set
 591  *
 592  * \return Group of enum pcmk__updated flags indicating what was updated
 593  */
 594 uint32_t
 595 pcmk__group_update_ordered_actions(pe_action_t *first, pe_action_t *then,
     /* [previous][next][first][last][top][bottom][index][help] */
 596                                    const pe_node_t *node, uint32_t flags,
 597                                    uint32_t filter, uint32_t type,
 598                                    pe_working_set_t *data_set)
 599 {
 600     uint32_t changed = pcmk__updated_none;
 601 
 602     CRM_ASSERT((first != NULL) && (then != NULL) && (data_set != NULL));
 603 
 604     // Group method can be called only for group action as "then" action
 605     CRM_ASSERT(then->rsc != NULL);
 606 
 607     // Update the actions for the group itself
 608     changed |= pcmk__update_ordered_actions(first, then, node, flags, filter,
 609                                             type, data_set);
 610 
 611     // Update the actions for each group member
 612     for (GList *iter = then->rsc->children; iter != NULL; iter = iter->next) {
 613         pe_resource_t *member = (pe_resource_t *) iter->data;
 614 
 615         pe_action_t *member_action = find_first_action(member->actions, NULL,
 616                                                        then->task, node);
 617 
 618         if (member_action != NULL) {
 619             changed |= member->cmds->update_ordered_actions(first,
 620                                                             member_action, node,
 621                                                             flags, filter, type,
 622                                                             data_set);
 623         }
 624     }
 625     return changed;
 626 }
 627 
 628 /*!
 629  * \internal
 630  * \brief Apply a location constraint to a group's allowed node scores
 631  *
 632  * \param[in,out] rsc       Group resource to apply constraint to
 633  * \param[in,out] location  Location constraint to apply
 634  */
 635 void
 636 pcmk__group_apply_location(pe_resource_t *rsc, pe__location_t *location)
     /* [previous][next][first][last][top][bottom][index][help] */
 637 {
 638     GList *node_list_orig = NULL;
 639     GList *node_list_copy = NULL;
 640     bool reset_scores = true;
 641 
 642     CRM_ASSERT((rsc != NULL) && (location != NULL));
 643 
 644     node_list_orig = location->node_list_rh;
 645     node_list_copy = pcmk__copy_node_list(node_list_orig, true);
 646     reset_scores = pe__group_flag_is_set(rsc, pe__group_colocated);
 647 
 648     // Apply the constraint for the group itself (updates node scores)
 649     pcmk__apply_location(rsc, location);
 650 
 651     // Apply the constraint for each member
 652     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 653         pe_resource_t *member = (pe_resource_t *) iter->data;
 654 
 655         member->cmds->apply_location(member, location);
 656 
 657         if (reset_scores) {
 658             /* The first member of colocated groups needs to use the original
 659              * node scores, but subsequent members should work on a copy, since
 660              * the first member's scores already incorporate theirs.
 661              */
 662             reset_scores = false;
 663             location->node_list_rh = node_list_copy;
 664         }
 665     }
 666 
 667     location->node_list_rh = node_list_orig;
 668     g_list_free_full(node_list_copy, free);
 669 }
 670 
 671 // Group implementation of resource_alloc_functions_t:colocated_resources()
 672 GList *
 673 pcmk__group_colocated_resources(pe_resource_t *rsc, pe_resource_t *orig_rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 674                                 GList *colocated_rscs)
 675 {
 676     pe_resource_t *member = NULL;
 677 
 678     CRM_ASSERT(rsc != NULL);
 679 
 680     if (orig_rsc == NULL) {
 681         orig_rsc = rsc;
 682     }
 683 
 684     if (pe__group_flag_is_set(rsc, pe__group_colocated)
 685         || pe_rsc_is_clone(rsc->parent)) {
 686         /* This group has colocated members and/or is cloned -- either way,
 687          * add every child's colocated resources to the list.
 688          */
 689         for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 690             member = (pe_resource_t *) iter->data;
 691             colocated_rscs = member->cmds->colocated_resources(member, orig_rsc,
 692                                                                colocated_rscs);
 693         }
 694 
 695     } else if (rsc->children != NULL) {
 696         /* This group's members are not colocated, and the group is not cloned,
 697          * so just add the first child's colocations to the list.
 698          */
 699         member = (pe_resource_t *) rsc->children->data;
 700         colocated_rscs = member->cmds->colocated_resources(member, orig_rsc,
 701                                                            colocated_rscs);
 702     }
 703 
 704     // Now consider colocations where the group itself is specified
 705     colocated_rscs = pcmk__colocated_resources(rsc, orig_rsc, colocated_rscs);
 706 
 707     return colocated_rscs;
 708 }
 709 
 710 // Group implementation of resource_alloc_functions_t:add_utilization()
 711 void
 712 pcmk__group_add_utilization(const pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 713                             const pe_resource_t *orig_rsc, GList *all_rscs,
 714                             GHashTable *utilization)
 715 {
 716     pe_resource_t *member = NULL;
 717 
 718     CRM_ASSERT((rsc != NULL) && (orig_rsc != NULL) && (utilization != NULL));
 719 
 720     if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
 721         return;
 722     }
 723 
 724     pe_rsc_trace(orig_rsc, "%s: Adding group %s as colocated utilization",
 725                  orig_rsc->id, rsc->id);
 726     if (pe__group_flag_is_set(rsc, pe__group_colocated)
 727         || pe_rsc_is_clone(rsc->parent)) {
 728         // Every group member will be on same node, so sum all members
 729         for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 730             member = (pe_resource_t *) iter->data;
 731 
 732             if (pcmk_is_set(member->flags, pe_rsc_provisional)
 733                 && (g_list_find(all_rscs, member) == NULL)) {
 734                 member->cmds->add_utilization(member, orig_rsc, all_rscs,
 735                                               utilization);
 736             }
 737         }
 738 
 739     } else if (rsc->children != NULL) {
 740         // Just add first member's utilization
 741         member = (pe_resource_t *) rsc->children->data;
 742         if ((member != NULL)
 743             && pcmk_is_set(member->flags, pe_rsc_provisional)
 744             && (g_list_find(all_rscs, member) == NULL)) {
 745 
 746             member->cmds->add_utilization(member, orig_rsc, all_rscs,
 747                                           utilization);
 748         }
 749     }
 750 }
 751 
 752 // Group implementation of resource_alloc_functions_t:shutdown_lock()
 753 void
 754 pcmk__group_shutdown_lock(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 755 {
 756     CRM_ASSERT(rsc != NULL);
 757 
 758     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 759         pe_resource_t *member = (pe_resource_t *) iter->data;
 760 
 761         member->cmds->shutdown_lock(member);
 762     }
 763 }

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