/* * 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 = pe__health_score(PCMK_OPT_NODE_HEALTH_RED, scheduler); pcmk__score_green = pe__health_score(PCMK_OPT_NODE_HEALTH_GREEN, scheduler); pcmk__score_yellow = pe__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); } } /*! * \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; *health = pcmk__add_scores(score, *health); crm_trace("Combined '%s' into node health score (now %s)", (const char *) value, pcmk_readable_score(*health)); } } /*! * \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) { CRM_ASSERT(node != NULL); g_hash_table_foreach(node->details->attrs, add_node_health_value, &base_health); return base_health; } /*! * \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->details->data_set); if (strategy == pcmk__health_strategy_none) { return rc; } g_hash_table_iter_init(&iter, node->details->attrs); while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &value)) { if (pcmk__starts_with(name, "#health")) { /* 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; } // 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; }