root/pengine/group.c

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

DEFINITIONS

This source file includes following definitions.
  1. group_color
  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. group_merge_weights
  12. group_append_meta

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

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