summaryrefslogtreecommitdiffstats
path: root/lib/pengine/pe_health.c
blob: 6419fdf04e408960d77ed85d54ec0aaee92f6519 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * Copyright 2004-2023 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 <crm_internal.h>

#include <crm/pengine/status.h>
#include <crm/pengine/internal.h>
#include "pe_status_private.h"

/*!
 * \internal
 * \brief Set the node health values to use for "red", "yellow", and "green"
 *
 * \param[in,out] data_set  Cluster working set
 */
void
pe__unpack_node_health_scores(pe_working_set_t *data_set)
{
    switch (pe__health_strategy(data_set)) {
        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 = -INFINITY;
            pcmk__score_yellow = 0;
            pcmk__score_green = 0;
            break;

        case pcmk__health_strategy_only_green:
            pcmk__score_red = -INFINITY;
            pcmk__score_yellow = -INFINITY;
            pcmk__score_green = 0;
            break;

        default: // progressive or custom
            pcmk__score_red = pe__health_score(PCMK__OPT_NODE_HEALTH_RED,
                                               data_set);
            pcmk__score_green = pe__health_score(PCMK__OPT_NODE_HEALTH_GREEN,
                                                 data_set);
            pcmk__score_yellow = pe__health_score(PCMK__OPT_NODE_HEALTH_YELLOW,
                                                  data_set);
            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 pe_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(pe_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;
}