diff -Nur pacemaker.orig/include/crm/common/util.h pacemaker.mark/include/crm/common/util.h --- pacemaker.orig/include/crm/common/util.h 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/include/crm/common/util.h 2009-05-15 13:43:09.000000000 -0500 @@ -166,7 +166,15 @@ extern gboolean check_boolean(const char *value); extern gboolean check_number(const char *value); -extern int char2score(const char *score); +struct health_scores_s { + int red_value; + int yellow_value; + int green_value; +}; + +typedef struct health_scores_s health_scores_t; + +extern int char2score(const char *score, health_scores_t *health_scores); extern char *score2char(int score); extern gboolean crm_is_writable( diff -Nur pacemaker.orig/lib/common/utils.c pacemaker.mark/lib/common/utils.c --- pacemaker.orig/lib/common/utils.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/lib/common/utils.c 2009-05-15 13:51:37.000000000 -0500 @@ -107,7 +107,7 @@ } int -char2score(const char *score) +char2score(const char *score, health_scores_t *health_scores) { int score_f = 0; @@ -122,6 +122,15 @@ } else if(safe_str_eq(score, "+"INFINITY_S)) { score_f = INFINITY; + } else if(health_scores && safe_str_eq(score, "red")) { + score_f = health_scores->red_value; + + } else if(health_scores && safe_str_eq(score, "yellow")) { + score_f = health_scores->yellow_value; + + } else if(health_scores && safe_str_eq(score, "green")) { + score_f = health_scores->green_value; + } else { score_f = crm_parse_int(score, NULL); if(score_f > 0 && score_f > INFINITY) { diff -Nur pacemaker.orig/lib/common/xml.c pacemaker.mark/lib/common/xml.c --- pacemaker.orig/lib/common/xml.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/lib/common/xml.c 2009-05-15 13:45:00.000000000 -0500 @@ -216,12 +216,12 @@ * then no previous value was set and leave int_value as 0 */ if(old_value != value) { - int_value = char2score(old_value); + int_value = char2score(old_value, NULL); } if(value[name_len+1] != '+') { const char *offset_s = value+(name_len+2); - offset = char2score(offset_s); + offset = char2score(offset_s, NULL); } int_value += offset; diff -Nur pacemaker.orig/lib/pengine/complex.c pacemaker.mark/lib/pengine/complex.c --- pacemaker.orig/lib/pengine/complex.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/lib/pengine/complex.c 2009-05-15 13:52:28.000000000 -0500 @@ -302,12 +302,12 @@ value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_STICKINESS); if(value != NULL && safe_str_neq("default", value)) { - (*rsc)->stickiness = char2score(value); + (*rsc)->stickiness = char2score(value, NULL); } value = g_hash_table_lookup((*rsc)->meta, XML_RSC_ATTR_FAIL_STICKINESS); if(value != NULL && safe_str_neq("default", value)) { - (*rsc)->migration_threshold = char2score(value); + (*rsc)->migration_threshold = char2score(value, NULL); } else if(value == NULL) { /* Make a best-effort guess at a migration threshold for people with 0.6 configs @@ -326,7 +326,7 @@ } if(value) { - int fail_sticky = char2score(value); + int fail_sticky = char2score(value, NULL); if(fail_sticky == -INFINITY) { (*rsc)->migration_threshold = 1; crm_info("Set a migration threshold for %s of %d based on a failure-stickiness of %s", diff -Nur pacemaker.orig/lib/pengine/rules.c pacemaker.mark/lib/pengine/rules.c --- pacemaker.orig/lib/pengine/rules.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/lib/pengine/rules.c 2009-05-15 13:53:04.000000000 -0500 @@ -626,7 +626,7 @@ pair->attr_set = attr_set; score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE); - pair->score = char2score(score); + pair->score = char2score(score, NULL); unsorted = g_list_append(unsorted, pair); ); diff -Nur pacemaker.orig/lib/pengine/unpack.c pacemaker.mark/lib/pengine/unpack.c --- pacemaker.orig/lib/pengine/unpack.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/lib/pengine/unpack.c 2009-05-15 13:53:29.000000000 -0500 @@ -85,7 +85,7 @@ } value = pe_pref(data_set->config_hash, "default-resource-stickiness"); - data_set->default_resource_stickiness = char2score(value); + data_set->default_resource_stickiness = char2score(value, NULL); crm_debug("Default stickiness: %d", data_set->default_resource_stickiness); diff -Nur pacemaker.orig/lib/pengine/utils.c pacemaker.mark/lib/pengine/utils.c --- pacemaker.orig/lib/pengine/utils.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/lib/pengine/utils.c 2009-05-15 13:53:53.000000000 -0500 @@ -1335,7 +1335,7 @@ } if(value != NULL) { - fail_count = char2score(value); + fail_count = char2score(value, NULL); crm_info("%s has failed %d times on %s", failed->id, fail_count, node->details->uname); } diff -Nur pacemaker.orig/pengine/allocate.c pacemaker.mark/pengine/allocate.c --- pacemaker.orig/pengine/allocate.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/pengine/allocate.c 2009-05-15 17:37:59.000000000 -0500 @@ -524,6 +524,199 @@ ); } +struct health_info_s { + health_scores_t health_scores; /* integer values for red, yellow, and green */ + int system_health; /* cumulative total of #health.* values found */ +}; + +typedef struct health_info_s health_info_t; + +void calculate_system_health (gpointer gKey, gpointer gValue, gpointer user_data); + +void +calculate_system_health (gpointer gKey, gpointer gValue, gpointer user_data) +{ + const char *key = (const char *)gKey; + const char *value = (const char *)gValue; + health_info_t *defaults = (health_info_t *)user_data; + + if (!gKey || !gValue || !user_data) { + return; + } + + /* Does it start with #health? */ + if (0 == strncmp (key, "#health", 7)) { + int score; + + /* Convert the value into an integer */ + score = char2score (value, &defaults->health_scores); + + /* Add it to the running total */ + defaults->system_health = merge_weights (score, defaults->system_health); + } +} + +gboolean initialize_health_value (int *value, int def, const char *search, pe_working_set_t *data_set); + +gboolean +initialize_health_value (int *value, int def, const char *search, pe_working_set_t *data_set) +{ + const char *attr_value = NULL; + + if (!value || !search || !data_set) { + return FALSE; + } + + *value = def; + + attr_value = g_hash_table_lookup (data_set->config_hash, search); + + if (attr_value) { + crm_debug_2 ("attr_value = %s", attr_value); + + *value = char2score (attr_value, NULL); + + return TRUE; + } + + return FALSE; +} + +gboolean apply_system_health_migrate_health_info (pe_working_set_t *data_set, health_info_t *health_info); + +gboolean +apply_system_health_migrate_health_info (pe_working_set_t *data_set, health_info_t *health_info) +{ + if (!data_set || !health_info) { + return FALSE; + } + + /* Loop over the resources */ + slist_iter( + rsc, resource_t, data_set->resources, lpc, + + /* Loop over the nodes */ + slist_iter( + + node, node_t, data_set->nodes, lpc, + + const char *id = "AutoGenSystemHealth"; + + health_info->system_health = 0; + + /* Search through the node hash table for system health entries. */ + g_hash_table_foreach ( + node->details->attrs, + calculate_system_health, + (gpointer)health_info); + + crm_info ("resource (%s) node (%s) has a total system health value of %d", + rsc->id, + node->details->uname, + health_info->system_health); + + /* If the health is non-zero, then create a new rsc2node so that the + * weight will be added later on. + */ + if (health_info->system_health != 0) { + rsc2node_new (id, rsc, health_info->system_health, node, data_set); + } + + ); + ); + + return TRUE; +} + +gboolean apply_system_health (pe_working_set_t *data_set); + +gboolean +apply_system_health(pe_working_set_t *data_set) +{ + const char *health_strategy = NULL; + health_info_t health_info; + + /* What is our strategy? */ + health_strategy = g_hash_table_lookup (data_set->config_hash, "pe-node-health-strategy"); + + if (!health_strategy) { + + /* Defaults to "none" which is do nothing. + */ + crm_info ("pe-node-health-strategy was not specified, defaulting to \"none\""); + + return TRUE; + + } else if (safe_str_eq (health_strategy, "none")) { + + /* Do nothing. + */ + crm_info ("pe-node-health-strategy was \"none\""); + + return TRUE; + + } else if (safe_str_eq (health_strategy, "custom")) { + + /* Requires the admin to configure the health weights manually. + */ + crm_info ("pe-node-health-strategy was \"custom\""); + + initialize_health_value (&health_info.health_scores.red_value, + -INFINITY, + "pe-node-health-score-red", + data_set); + initialize_health_value (&health_info.health_scores.yellow_value, + 0, + "pe-node-health-score-yellow", + data_set); + initialize_health_value (&health_info.health_scores.green_value, + 0, + "pe-node-health-score-green", + data_set); + + crm_info ("red health value is %s", score2char (health_info.health_scores.red_value)); + crm_info ("yellow health value is %s", score2char (health_info.health_scores.yellow_value)); + crm_info ("green health value is %s", score2char (health_info.health_scores.green_value)); + + return apply_system_health_migrate_health_info (data_set, &health_info); + + } else if (safe_str_eq (health_strategy, "migrate-on-red")) { + + /* Resources on nodes which have health values of red are + * weighted away from that node. + */ + crm_info ("pe-node-health-strategy was \"migrate-on-red\""); + + health_info.health_scores.red_value = -INFINITY; + health_info.health_scores.yellow_value = 0; + health_info.health_scores.green_value = 0; + + return apply_system_health_migrate_health_info (data_set, &health_info); + + } else if (safe_str_eq (health_strategy, "migrate-on-not-green")) { + + /* Resources on nodes which have health values of red or yellow + * are weighted away from that node. + */ + crm_info ("pe-node-health-strategy was \"migrate-on-not-green\""); + + health_info.health_scores.red_value = -INFINITY; + health_info.health_scores.yellow_value = -INFINITY; + health_info.health_scores.green_value = 0; + + return apply_system_health_migrate_health_info (data_set, &health_info); + + } else { + + crm_err ("A pe-node-health-strategy of \"%s\" is not understood!", health_strategy); + + return FALSE; + + } + + return FALSE; +} + gboolean stage0(pe_working_set_t *data_set) { @@ -539,6 +732,8 @@ set_alloc_actions(data_set); unpack_constraints(cib_constraints, data_set); + apply_system_health(data_set); + return TRUE; } diff -Nur pacemaker.orig/pengine/constraints.c pacemaker.mark/pengine/constraints.c --- pacemaker.orig/pengine/constraints.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/pengine/constraints.c 2009-05-15 13:55:37.000000000 -0500 @@ -177,7 +177,7 @@ score = "INFINITY"; } - score_i = char2score(score); + score_i = char2score(score, NULL); cons_weight = pe_order_optional; if(score_i == 0 && rsc_then->restart_type == pe_restart_restart) { crm_debug_2("Upgrade : recovery - implies right"); @@ -270,7 +270,7 @@ } if(node != NULL && score != NULL) { - int score_i = char2score(score); + int score_i = char2score(score, NULL); node_t *match = pe_find_node(data_set->nodes, node); if(match) { @@ -304,7 +304,7 @@ pe_err("Rule %s: no score specified. Assuming 0.", rule); } else if(raw) { - score_f = char2score(score); + score_f = char2score(score, NULL); } else { const char *attr_score = g_hash_table_lookup( @@ -317,7 +317,7 @@ } else { crm_debug("Rule %s: node %s had value %s for %s", rule, node->details->uname, attr_score, score); - score_f = char2score(attr_score); + score_f = char2score(attr_score, NULL); } } return score_f; @@ -356,7 +356,7 @@ score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE); if(score != NULL) { - score_f = char2score(score); + score_f = char2score(score, NULL); } else { score = crm_element_value( @@ -723,7 +723,7 @@ *begin = get_pseudo_op(begin_id, data_set); if(score_s) { - local_score = char2score(score_s); + local_score = char2score(score_s, NULL); } sequential = crm_is_true(sequential_s); @@ -889,7 +889,7 @@ score = "INFINITY"; } - score_i = char2score(score); + score_i = char2score(score, NULL); xml_child_iter_filter( xml_obj, set, "resource_set", @@ -944,7 +944,7 @@ const char *score_s = crm_element_value(set, XML_RULE_ATTR_SCORE); if(score_s) { - local_score = char2score(score_s); + local_score = char2score(score_s, NULL); } if(crm_is_true(sequential)) { @@ -1064,7 +1064,7 @@ } if(score) { - score_i = char2score(score); + score_i = char2score(score, NULL); } rsc_colocation_new(id, attr, score_i, rsc_lh, rsc_rh, state_lh, state_rh, data_set); @@ -1082,7 +1082,7 @@ const char *score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE); if(score) { - score_i = char2score(score); + score_i = char2score(score, NULL); } xml_child_iter_filter( diff -Nur pacemaker.orig/pengine/master.c pacemaker.mark/pengine/master.c --- pacemaker.orig/pengine/master.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/pengine/master.c 2009-05-15 13:56:02.000000000 -0500 @@ -397,7 +397,7 @@ if(attr_value != NULL) { crm_debug_2("%s[%s] = %s", attr_name, node->details->uname, crm_str(attr_value)); - score = char2score(attr_value); + score = char2score(attr_value, NULL); } crm_free(attr_name); diff -Nur pacemaker.orig/tools/crm_attribute.c pacemaker.mark/tools/crm_attribute.c --- pacemaker.orig/tools/crm_attribute.c 2009-04-08 02:49:50.000000000 -0500 +++ pacemaker.mark/tools/crm_attribute.c 2009-05-15 13:56:19.000000000 -0500 @@ -336,7 +336,7 @@ goto bail; } - if(DO_WRITE && char2score(attr_value) <= 0) { + if(DO_WRITE && char2score(attr_value, NULL) <= 0) { if(safe_str_neq(attr_value, "0")) { fprintf(stderr,"%s is an inappropriate value for a failcount.\n", attr_value); rc = CIBRES_MISSING_FIELD;