root/lib/pacemaker/pcmk_sched_group.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk__group_allocate
  2. group_create_actions
  3. group_update_pseudo_status
  4. group_internal_constraints
  5. group_rsc_colocation_lh
  6. group_rsc_colocation_rh
  7. group_action_flags
  8. group_update_actions
  9. group_rsc_location
  10. group_expand
  11. pcmk__group_merge_weights
  12. group_append_meta

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

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