Line data Source code
1 : /* 2 : * Copyright 2004-2024 the Pacemaker project contributors 3 : * 4 : * The version control history for this file may have further details. 5 : * 6 : * This source code is licensed under the GNU Lesser General Public License 7 : * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. 8 : */ 9 : 10 : #include <crm_internal.h> 11 : 12 : #include <crm/pengine/status.h> 13 : #include <crm/pengine/internal.h> 14 : #include "pe_status_private.h" 15 : 16 : /*! 17 : * \internal 18 : * \brief Set the node health values to use for \c PCMK_VALUE_RED, 19 : * \c PCMK_VALUE_YELLOW, and \c PCMK_VALUE_GREEN 20 : * 21 : * \param[in,out] scheduler Scheduler data 22 : */ 23 : void 24 0 : pe__unpack_node_health_scores(pcmk_scheduler_t *scheduler) 25 : { 26 0 : switch (pe__health_strategy(scheduler)) { 27 0 : case pcmk__health_strategy_none: 28 0 : pcmk__score_red = 0; 29 0 : pcmk__score_yellow = 0; 30 0 : pcmk__score_green = 0; 31 0 : break; 32 : 33 0 : case pcmk__health_strategy_no_red: 34 0 : pcmk__score_red = -PCMK_SCORE_INFINITY; 35 0 : pcmk__score_yellow = 0; 36 0 : pcmk__score_green = 0; 37 0 : break; 38 : 39 0 : case pcmk__health_strategy_only_green: 40 0 : pcmk__score_red = -PCMK_SCORE_INFINITY; 41 0 : pcmk__score_yellow = -PCMK_SCORE_INFINITY; 42 0 : pcmk__score_green = 0; 43 0 : break; 44 : 45 0 : default: // progressive or custom 46 0 : pcmk__score_red = pe__health_score(PCMK_OPT_NODE_HEALTH_RED, 47 : scheduler); 48 0 : pcmk__score_green = pe__health_score(PCMK_OPT_NODE_HEALTH_GREEN, 49 : scheduler); 50 0 : pcmk__score_yellow = pe__health_score(PCMK_OPT_NODE_HEALTH_YELLOW, 51 : scheduler); 52 0 : break; 53 : } 54 : 55 0 : if ((pcmk__score_red != 0) || (pcmk__score_yellow != 0) 56 0 : || (pcmk__score_green != 0)) { 57 0 : crm_debug("Values of node health scores: " 58 : PCMK_VALUE_RED "=%d " 59 : PCMK_VALUE_YELLOW "=%d " 60 : PCMK_VALUE_GREEN "=%d", 61 : pcmk__score_red, pcmk__score_yellow, pcmk__score_green); 62 : } 63 0 : } 64 : 65 : /*! 66 : * \internal 67 : * \brief Add node attribute value to an integer, if it is a health attribute 68 : * 69 : * \param[in] key Name of node attribute 70 : * \param[in] value String value of node attribute 71 : * \param[in,out] user_data Address of integer to which \p value should be 72 : * added if \p key is a node health attribute 73 : */ 74 : static void 75 0 : add_node_health_value(gpointer key, gpointer value, gpointer user_data) 76 : { 77 0 : if (pcmk__starts_with((const char *) key, "#health")) { 78 0 : int score = char2score((const char *) value); 79 0 : int *health = (int *) user_data; 80 : 81 0 : *health = pcmk__add_scores(score, *health); 82 0 : crm_trace("Combined '%s' into node health score (now %s)", 83 : (const char *) value, pcmk_readable_score(*health)); 84 : } 85 0 : } 86 : 87 : /*! 88 : * \internal 89 : * \brief Sum a node's health attribute scores 90 : * 91 : * \param[in] node Node whose health attributes should be added 92 : * \param[in] base_health Add this number to the total 93 : * 94 : * \return Sum of all health attribute scores of \p node plus \p base_health 95 : */ 96 : int 97 0 : pe__sum_node_health_scores(const pcmk_node_t *node, int base_health) 98 : { 99 0 : CRM_ASSERT(node != NULL); 100 0 : g_hash_table_foreach(node->details->attrs, add_node_health_value, 101 : &base_health); 102 0 : return base_health; 103 : } 104 : 105 : /*! 106 : * \internal 107 : * \brief Check the general health status for a node 108 : * 109 : * \param[in,out] node Node to check 110 : * 111 : * \return A negative value if any health attribute for \p node is red, 112 : * otherwise 0 if any attribute is yellow, otherwise a positive value. 113 : */ 114 : int 115 0 : pe__node_health(pcmk_node_t *node) 116 : { 117 : GHashTableIter iter; 118 0 : const char *name = NULL; 119 0 : const char *value = NULL; 120 : enum pcmk__health_strategy strategy; 121 0 : int score = 0; 122 0 : int rc = 1; 123 : 124 0 : CRM_ASSERT(node != NULL); 125 : 126 0 : strategy = pe__health_strategy(node->details->data_set); 127 0 : if (strategy == pcmk__health_strategy_none) { 128 0 : return rc; 129 : } 130 : 131 0 : g_hash_table_iter_init(&iter, node->details->attrs); 132 0 : while (g_hash_table_iter_next(&iter, (gpointer *) &name, 133 : (gpointer *) &value)) { 134 0 : if (pcmk__starts_with(name, "#health")) { 135 : /* It's possible that pcmk__score_red equals pcmk__score_yellow, 136 : * or pcmk__score_yellow equals pcmk__score_green, so check the 137 : * textual value first to be able to distinguish those. 138 : */ 139 0 : if (pcmk__str_eq(value, PCMK_VALUE_RED, pcmk__str_casei)) { 140 0 : return -1; 141 0 : } else if (pcmk__str_eq(value, PCMK_VALUE_YELLOW, 142 : pcmk__str_casei)) { 143 0 : rc = 0; 144 0 : continue; 145 : } 146 : 147 : // The value is an integer, so compare numerically 148 0 : score = char2score(value); 149 0 : if (score <= pcmk__score_red) { 150 0 : return -1; 151 0 : } else if ((score <= pcmk__score_yellow) 152 0 : && (pcmk__score_yellow != pcmk__score_green)) { 153 0 : rc = 0; 154 : } 155 : } 156 : } 157 0 : return rc; 158 : }