root/pengine/utils.c

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

DEFINITIONS

This source file includes following definitions.
  1. pe_free_ordering
  2. pe_free_rsc_to_node
  3. rsc2node_new
  4. can_run_resources
  5. sort_node_weight
  6. native_deallocate
  7. native_assign_node
  8. log_action
  9. can_run_any
  10. create_pseudo_resource_op

   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 #include <crm/msg_xml.h>
  21 #include <allocate.h>
  22 #include <utils.h>
  23 
  24 void
  25 pe_free_ordering(GListPtr constraints)
     /* [previous][next][first][last][top][bottom][index][help] */
  26 {
  27     GListPtr iterator = constraints;
  28 
  29     while (iterator != NULL) {
  30         order_constraint_t *order = iterator->data;
  31 
  32         iterator = iterator->next;
  33 
  34         free(order->lh_action_task);
  35         free(order->rh_action_task);
  36         free(order);
  37     }
  38     if (constraints != NULL) {
  39         g_list_free(constraints);
  40     }
  41 }
  42 
  43 void
  44 pe_free_rsc_to_node(GListPtr constraints)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46     GListPtr iterator = constraints;
  47 
  48     while (iterator != NULL) {
  49         rsc_to_node_t *cons = iterator->data;
  50 
  51         iterator = iterator->next;
  52 
  53         g_list_free_full(cons->node_list_rh, free);
  54         free(cons->id);
  55         free(cons);
  56     }
  57     if (constraints != NULL) {
  58         g_list_free(constraints);
  59     }
  60 }
  61 
  62 rsc_to_node_t *
  63 rsc2node_new(const char *id, resource_t * rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
  64              int node_weight, const char *discover_mode,
  65              node_t * foo_node, pe_working_set_t * data_set)
  66 {
  67     rsc_to_node_t *new_con = NULL;
  68 
  69     if (rsc == NULL || id == NULL) {
  70         pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc);
  71         return NULL;
  72 
  73     } else if (foo_node == NULL) {
  74         CRM_CHECK(node_weight == 0, return NULL);
  75     }
  76 
  77     new_con = calloc(1, sizeof(rsc_to_node_t));
  78     if (new_con != NULL) {
  79         new_con->id = strdup(id);
  80         new_con->rsc_lh = rsc;
  81         new_con->node_list_rh = NULL;
  82         new_con->role_filter = RSC_ROLE_UNKNOWN;
  83 
  84 
  85         if (discover_mode == NULL || safe_str_eq(discover_mode, "always")) {
  86             new_con->discover_mode = pe_discover_always;
  87         } else if (safe_str_eq(discover_mode, "never")) {
  88             new_con->discover_mode = pe_discover_never;
  89         } else if (safe_str_eq(discover_mode, "exclusive")) {
  90             new_con->discover_mode = pe_discover_exclusive;
  91             rsc->exclusive_discover = TRUE;
  92         } else {
  93             pe_err("Invalid %s value %s in location constraint", XML_LOCATION_ATTR_DISCOVERY, discover_mode);
  94         }
  95 
  96         if (foo_node != NULL) {
  97             node_t *copy = node_copy(foo_node);
  98 
  99             copy->weight = node_weight;
 100             new_con->node_list_rh = g_list_prepend(NULL, copy);
 101         }
 102 
 103         data_set->placement_constraints = g_list_prepend(data_set->placement_constraints, new_con);
 104         rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
 105     }
 106 
 107     return new_con;
 108 }
 109 
 110 gboolean
 111 can_run_resources(const node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113     if (node == NULL) {
 114         return FALSE;
 115     }
 116 #if 0
 117     if (node->weight < 0) {
 118         return FALSE;
 119     }
 120 #endif
 121 
 122     if (node->details->online == FALSE
 123         || node->details->shutdown || node->details->unclean
 124         || node->details->standby || node->details->maintenance) {
 125         crm_trace("%s: online=%d, unclean=%d, standby=%d, maintenance=%d",
 126                   node->details->uname, node->details->online,
 127                   node->details->unclean, node->details->standby, node->details->maintenance);
 128         return FALSE;
 129     }
 130     return TRUE;
 131 }
 132 
 133 /* return -1 if 'a' is more preferred
 134  * return  1 if 'b' is more preferred
 135  */
 136 
 137 gint
 138 sort_node_weight(gconstpointer a, gconstpointer b, gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140     const node_t *node1 = (const node_t *)a;
 141     const node_t *node2 = (const node_t *)b;
 142     const node_t *active = (node_t *) data;
 143 
 144     int node1_weight = 0;
 145     int node2_weight = 0;
 146 
 147     int result = 0;
 148 
 149     if (a == NULL) {
 150         return 1;
 151     }
 152     if (b == NULL) {
 153         return -1;
 154     }
 155 
 156     node1_weight = node1->weight;
 157     node2_weight = node2->weight;
 158 
 159     if (can_run_resources(node1) == FALSE) {
 160         node1_weight = -INFINITY;
 161     }
 162     if (can_run_resources(node2) == FALSE) {
 163         node2_weight = -INFINITY;
 164     }
 165 
 166     if (node1_weight > node2_weight) {
 167         crm_trace("%s (%d) > %s (%d) : weight",
 168                   node1->details->uname, node1_weight, node2->details->uname, node2_weight);
 169         return -1;
 170     }
 171 
 172     if (node1_weight < node2_weight) {
 173         crm_trace("%s (%d) < %s (%d) : weight",
 174                   node1->details->uname, node1_weight, node2->details->uname, node2_weight);
 175         return 1;
 176     }
 177 
 178     crm_trace("%s (%d) == %s (%d) : weight",
 179               node1->details->uname, node1_weight, node2->details->uname, node2_weight);
 180 
 181     if (safe_str_eq(pe_dataset->placement_strategy, "minimal")) {
 182         goto equal;
 183     }
 184 
 185     if (safe_str_eq(pe_dataset->placement_strategy, "balanced")) {
 186         result = compare_capacity(node1, node2);
 187         if (result < 0) {
 188             crm_trace("%s > %s : capacity (%d)",
 189                       node1->details->uname, node2->details->uname, result);
 190             return -1;
 191         } else if (result > 0) {
 192             crm_trace("%s < %s : capacity (%d)",
 193                       node1->details->uname, node2->details->uname, result);
 194             return 1;
 195         }
 196     }
 197 
 198     /* now try to balance resources across the cluster */
 199     if (node1->details->num_resources < node2->details->num_resources) {
 200         crm_trace("%s (%d) > %s (%d) : resources",
 201                   node1->details->uname, node1->details->num_resources,
 202                   node2->details->uname, node2->details->num_resources);
 203         return -1;
 204 
 205     } else if (node1->details->num_resources > node2->details->num_resources) {
 206         crm_trace("%s (%d) < %s (%d) : resources",
 207                   node1->details->uname, node1->details->num_resources,
 208                   node2->details->uname, node2->details->num_resources);
 209         return 1;
 210     }
 211 
 212     if (active && active->details == node1->details) {
 213         crm_trace("%s (%d) > %s (%d) : active",
 214                   node1->details->uname, node1->details->num_resources,
 215                   node2->details->uname, node2->details->num_resources);
 216         return -1;
 217     } else if (active && active->details == node2->details) {
 218         crm_trace("%s (%d) < %s (%d) : active",
 219                   node1->details->uname, node1->details->num_resources,
 220                   node2->details->uname, node2->details->num_resources);
 221         return 1;
 222     }
 223   equal:
 224     crm_trace("%s = %s", node1->details->uname, node2->details->uname);
 225     return strcmp(node1->details->uname, node2->details->uname);
 226 }
 227 
 228 void
 229 native_deallocate(resource_t * rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231     if (rsc->allocated_to) {
 232         node_t *old = rsc->allocated_to;
 233 
 234         crm_info("Deallocating %s from %s", rsc->id, old->details->uname);
 235         set_bit(rsc->flags, pe_rsc_provisional);
 236         rsc->allocated_to = NULL;
 237 
 238         old->details->allocated_rsc = g_list_remove(old->details->allocated_rsc, rsc);
 239         old->details->num_resources--;
 240         /* old->count--; */
 241         calculate_utilization(old->details->utilization, rsc->utilization, TRUE);
 242         free(old);
 243     }
 244 }
 245 
 246 gboolean
 247 native_assign_node(resource_t * rsc, GListPtr nodes, node_t * chosen, gboolean force)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249     CRM_ASSERT(rsc->variant == pe_native);
 250 
 251     if (force == FALSE && chosen != NULL) {
 252         bool unset = FALSE;
 253 
 254         if(chosen->weight < 0) {
 255             unset = TRUE;
 256 
 257             // Allow the graph to assume that the remote resource will come up
 258         } else if(can_run_resources(chosen) == FALSE && !is_container_remote_node(chosen)) {
 259             unset = TRUE;
 260         }
 261 
 262         if(unset) {
 263             crm_debug("All nodes for resource %s are unavailable"
 264                       ", unclean or shutting down (%s: %d, %d)",
 265                       rsc->id, chosen->details->uname, can_run_resources(chosen), chosen->weight);
 266             rsc->next_role = RSC_ROLE_STOPPED;
 267             chosen = NULL;
 268         }
 269     }
 270 
 271     /* todo: update the old node for each resource to reflect its
 272      * new resource count
 273      */
 274 
 275     native_deallocate(rsc);
 276     clear_bit(rsc->flags, pe_rsc_provisional);
 277 
 278     if (chosen == NULL) {
 279         GListPtr gIter = NULL;
 280         char *rc_inactive = crm_itoa(PCMK_OCF_NOT_RUNNING);
 281 
 282         crm_debug("Could not allocate a node for %s", rsc->id);
 283         rsc->next_role = RSC_ROLE_STOPPED;
 284 
 285         for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
 286             action_t *op = (action_t *) gIter->data;
 287             const char *interval = g_hash_table_lookup(op->meta, XML_LRM_ATTR_INTERVAL);
 288 
 289             crm_debug("Processing %s", op->uuid);
 290             if(safe_str_eq(RSC_STOP, op->task)) {
 291                 update_action_flags(op, pe_action_optional | pe_action_clear, __FUNCTION__, __LINE__);
 292 
 293             } else if(safe_str_eq(RSC_START, op->task)) {
 294                 update_action_flags(op, pe_action_runnable | pe_action_clear, __FUNCTION__, __LINE__);
 295                 /* set_bit(rsc->flags, pe_rsc_block); */
 296 
 297             } else if(interval && safe_str_neq(interval, "0")) {
 298                 if(safe_str_eq(rc_inactive, g_hash_table_lookup(op->meta, XML_ATTR_TE_TARGET_RC))) {
 299                     /* This is a recurring monitor for the stopped state, leave it alone */
 300 
 301                 } else {
 302                     /* Normal monitor operation, cancel it */
 303                     update_action_flags(op, pe_action_runnable | pe_action_clear, __FUNCTION__, __LINE__);
 304                 }
 305             }
 306         }
 307 
 308         free(rc_inactive);
 309         return FALSE;
 310     }
 311 
 312     crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id);
 313     rsc->allocated_to = node_copy(chosen);
 314 
 315     chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc, rsc);
 316     chosen->details->num_resources++;
 317     chosen->count++;
 318     calculate_utilization(chosen->details->utilization, rsc->utilization, FALSE);
 319     dump_rsc_utilization(show_utilization ? 0 : utilization_log_level, __FUNCTION__, rsc, chosen);
 320 
 321     return TRUE;
 322 }
 323 
 324 void
 325 log_action(unsigned int log_level, const char *pre_text, action_t * action, gboolean details)
     /* [previous][next][first][last][top][bottom][index][help] */
 326 {
 327     const char *node_uname = NULL;
 328     const char *node_uuid = NULL;
 329 
 330     if (action == NULL) {
 331         crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
 332         return;
 333     }
 334 
 335     if (is_set(action->flags, pe_action_pseudo)) {
 336         node_uname = NULL;
 337         node_uuid = NULL;
 338 
 339     } else if (action->node != NULL) {
 340         node_uname = action->node->details->uname;
 341         node_uuid = action->node->details->id;
 342     } else {
 343         node_uname = "<none>";
 344         node_uuid = NULL;
 345     }
 346 
 347     switch (text2task(action->task)) {
 348         case stonith_node:
 349         case shutdown_crm:
 350             crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
 351                       pre_text == NULL ? "" : pre_text,
 352                       pre_text == NULL ? "" : ": ",
 353                       is_set(action->flags,
 354                              pe_action_pseudo) ? "Pseudo " : is_set(action->flags,
 355                                                                     pe_action_optional) ?
 356                       "Optional " : is_set(action->flags,
 357                                            pe_action_runnable) ? is_set(action->flags,
 358                                                                         pe_action_processed)
 359                       ? "" : "(Provisional) " : "!!Non-Startable!! ", action->id,
 360                       action->uuid, node_uname ? "\ton " : "",
 361                       node_uname ? node_uname : "", node_uuid ? "\t\t(" : "",
 362                       node_uuid ? node_uuid : "", node_uuid ? ")" : "");
 363             break;
 364         default:
 365             crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
 366                       pre_text == NULL ? "" : pre_text,
 367                       pre_text == NULL ? "" : ": ",
 368                       is_set(action->flags,
 369                              pe_action_optional) ? "Optional " : is_set(action->flags,
 370                                                                         pe_action_pseudo)
 371                       ? "Pseudo " : is_set(action->flags,
 372                                            pe_action_runnable) ? is_set(action->flags,
 373                                                                         pe_action_processed)
 374                       ? "" : "(Provisional) " : "!!Non-Startable!! ", action->id,
 375                       action->uuid, action->rsc ? action->rsc->id : "<none>",
 376                       node_uname ? "\ton " : "", node_uname ? node_uname : "",
 377                       node_uuid ? "\t\t(" : "", node_uuid ? node_uuid : "", node_uuid ? ")" : "");
 378 
 379             break;
 380     }
 381 
 382     if (details) {
 383         GListPtr gIter = NULL;
 384 
 385         crm_trace("\t\t====== Preceding Actions");
 386 
 387         gIter = action->actions_before;
 388         for (; gIter != NULL; gIter = gIter->next) {
 389             action_wrapper_t *other = (action_wrapper_t *) gIter->data;
 390 
 391             log_action(log_level + 1, "\t\t", other->action, FALSE);
 392         }
 393 
 394         crm_trace("\t\t====== Subsequent Actions");
 395 
 396         gIter = action->actions_after;
 397         for (; gIter != NULL; gIter = gIter->next) {
 398             action_wrapper_t *other = (action_wrapper_t *) gIter->data;
 399 
 400             log_action(log_level + 1, "\t\t", other->action, FALSE);
 401         }
 402 
 403         crm_trace("\t\t====== End");
 404 
 405     } else {
 406         crm_trace("\t\t(seen=%d, before=%d, after=%d)",
 407                   action->seen_count,
 408                   g_list_length(action->actions_before), g_list_length(action->actions_after));
 409     }
 410 }
 411 
 412 gboolean
 413 can_run_any(GHashTable * nodes)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {
 415     GHashTableIter iter;
 416     node_t *node = NULL;
 417 
 418     if (nodes == NULL) {
 419         return FALSE;
 420     }
 421 
 422     g_hash_table_iter_init(&iter, nodes);
 423     while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 424         if (can_run_resources(node) && node->weight >= 0) {
 425             return TRUE;
 426         }
 427     }
 428 
 429     return FALSE;
 430 }
 431 
 432 pe_action_t *
 433 create_pseudo_resource_op(resource_t * rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 434 {
 435     pe_action_t *action = custom_action(rsc, generate_op_key(rsc->id, task, 0), task, NULL, optional, TRUE, data_set);
 436     update_action_flags(action, pe_action_pseudo, __FUNCTION__, __LINE__);
 437     update_action_flags(action, pe_action_runnable, __FUNCTION__, __LINE__);
 438     if(runnable) {
 439         update_action_flags(action, pe_action_runnable, __FUNCTION__, __LINE__);
 440     }
 441     return action;
 442 }

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