diff --git a/lib/pengine/pe_health.c b/lib/pengine/pe_health.c index 7383761500..bfc1963de0 100644 --- a/lib/pengine/pe_health.c +++ b/lib/pengine/pe_health.c @@ -1,158 +1,183 @@ /* * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include "pe_status_private.h" /*! * \internal * \brief Set the node health values to use for \c PCMK_VALUE_RED, * \c PCMK_VALUE_YELLOW, and \c PCMK_VALUE_GREEN * * \param[in,out] scheduler Scheduler data */ void pe__unpack_node_health_scores(pcmk_scheduler_t *scheduler) { switch (pe__health_strategy(scheduler)) { case pcmk__health_strategy_none: pcmk__score_red = 0; pcmk__score_yellow = 0; pcmk__score_green = 0; break; case pcmk__health_strategy_no_red: pcmk__score_red = -PCMK_SCORE_INFINITY; pcmk__score_yellow = 0; pcmk__score_green = 0; break; case pcmk__health_strategy_only_green: pcmk__score_red = -PCMK_SCORE_INFINITY; pcmk__score_yellow = -PCMK_SCORE_INFINITY; pcmk__score_green = 0; break; default: // progressive or custom pcmk__score_red = pcmk__health_score(PCMK_OPT_NODE_HEALTH_RED, scheduler); pcmk__score_green = pcmk__health_score(PCMK_OPT_NODE_HEALTH_GREEN, scheduler); pcmk__score_yellow = pcmk__health_score(PCMK_OPT_NODE_HEALTH_YELLOW, scheduler); break; } if ((pcmk__score_red != 0) || (pcmk__score_yellow != 0) || (pcmk__score_green != 0)) { crm_debug("Values of node health scores: " PCMK_VALUE_RED "=%d " PCMK_VALUE_YELLOW "=%d " PCMK_VALUE_GREEN "=%d", pcmk__score_red, pcmk__score_yellow, pcmk__score_green); } } +struct health_sum { + const pcmk_node_t *node; // Node that health score is being summed for + int sum; // Sum of health scores checked so far +}; + /*! * \internal * \brief Add node attribute value to an integer, if it is a health attribute * * \param[in] key Name of node attribute * \param[in] value String value of node attribute * \param[in,out] user_data Address of integer to which \p value should be * added if \p key is a node health attribute */ static void add_node_health_value(gpointer key, gpointer value, gpointer user_data) { if (pcmk__starts_with((const char *) key, "#health")) { - int score = char2score((const char *) value); - int *health = (int *) user_data; + struct health_sum *health_sum = user_data; + int score = 0; + int rc = pcmk_parse_score((const char *) value, &score, 0); + + if (rc != pcmk_rc_ok) { + crm_warn("Ignoring %s for %s because '%s' is not a valid value: %s", + (const char *) key, pcmk__node_name(health_sum->node), + (const char *) value, pcmk_rc_str(rc)); + return; + } - *health = pcmk__add_scores(score, *health); + health_sum->sum = pcmk__add_scores(score, health_sum->sum); crm_trace("Combined '%s' into node health score (now %s)", - (const char *) value, pcmk_readable_score(*health)); + (const char *) value, pcmk_readable_score(health_sum->sum)); } } /*! * \internal * \brief Sum a node's health attribute scores * * \param[in] node Node whose health attributes should be added * \param[in] base_health Add this number to the total * * \return Sum of all health attribute scores of \p node plus \p base_health */ int pe__sum_node_health_scores(const pcmk_node_t *node, int base_health) { + struct health_sum health_sum = { node, base_health, }; + CRM_ASSERT(node != NULL); g_hash_table_foreach(node->priv->attrs, add_node_health_value, - &base_health); - return base_health; + &health_sum); + return health_sum.sum; } /*! * \internal * \brief Check the general health status for a node * * \param[in,out] node Node to check * * \return A negative value if any health attribute for \p node is red, * otherwise 0 if any attribute is yellow, otherwise a positive value. */ int pe__node_health(pcmk_node_t *node) { GHashTableIter iter; const char *name = NULL; const char *value = NULL; enum pcmk__health_strategy strategy; int score = 0; int rc = 1; CRM_ASSERT(node != NULL); strategy = pe__health_strategy(node->priv->scheduler); if (strategy == pcmk__health_strategy_none) { return rc; } g_hash_table_iter_init(&iter, node->priv->attrs); while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &value)) { if (pcmk__starts_with(name, "#health")) { + int parse_rc = pcmk_rc_ok; + /* It's possible that pcmk__score_red equals pcmk__score_yellow, * or pcmk__score_yellow equals pcmk__score_green, so check the * textual value first to be able to distinguish those. */ if (pcmk__str_eq(value, PCMK_VALUE_RED, pcmk__str_casei)) { return -1; } else if (pcmk__str_eq(value, PCMK_VALUE_YELLOW, pcmk__str_casei)) { rc = 0; continue; } + parse_rc = pcmk_parse_score(value, &score, 0); + if (parse_rc != pcmk_rc_ok) { + crm_warn("Ignoring %s for %s " + "because '%s' is not a valid value: %s", + name, pcmk__node_name(node), value, + pcmk_rc_str(parse_rc)); + continue; + } + // The value is an integer, so compare numerically - score = char2score(value); if (score <= pcmk__score_red) { return -1; } else if ((score <= pcmk__score_yellow) && (pcmk__score_yellow != pcmk__score_green)) { rc = 0; } } } return rc; }