pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
pcmk_sched_nodes.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 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 General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11#include <crm/msg_xml.h>
12#include <crm/lrmd.h> // lrmd_event_data_t
14#include <pacemaker-internal.h>
15#include <pacemaker.h>
17
27bool
29{
30 // @TODO Should we add (node->weight >= 0)?
31 return (node != NULL) && (node->details != NULL) && node->details->online
32 && !node->details->shutdown && !node->details->unclean
33 && !node->details->standby && !node->details->maintenance;
34}
35
44GHashTable *
45pcmk__copy_node_table(GHashTable *nodes)
46{
47 GHashTable *new_table = NULL;
48 GHashTableIter iter;
49 pe_node_t *node = NULL;
50
51 if (nodes == NULL) {
52 return NULL;
53 }
54 new_table = pcmk__strkey_table(NULL, free);
55 g_hash_table_iter_init(&iter, nodes);
56 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
57 pe_node_t *new_node = pe__copy_node(node);
58
59 g_hash_table_insert(new_table, (gpointer) new_node->details->id,
60 new_node);
61 }
62 return new_table;
63}
64
74GList *
75pcmk__copy_node_list(const GList *list, bool reset)
76{
77 GList *result = NULL;
78
79 for (const GList *gIter = list; gIter != NULL; gIter = gIter->next) {
80 pe_node_t *new_node = NULL;
81 pe_node_t *this_node = (pe_node_t *) gIter->data;
82
83 new_node = pe__copy_node(this_node);
84 if (reset) {
85 new_node->weight = 0;
86 }
87 result = g_list_prepend(result, new_node);
88 }
89 return result;
90}
91
92struct node_weight_s {
93 pe_node_t *active;
95};
96
111static gint
112compare_nodes(gconstpointer a, gconstpointer b, gpointer data)
113{
114 const pe_node_t *node1 = (const pe_node_t *) a;
115 const pe_node_t *node2 = (const pe_node_t *) b;
116 struct node_weight_s *nw = data;
117
118 int node1_weight = 0;
119 int node2_weight = 0;
120
121 int result = 0;
122
123 if (a == NULL) {
124 return 1;
125 }
126 if (b == NULL) {
127 return -1;
128 }
129
130 // Compare node weights
131
132 node1_weight = pcmk__node_available(node1)? node1->weight : -INFINITY;
133 node2_weight = pcmk__node_available(node2)? node2->weight : -INFINITY;
134
135 if (node1_weight > node2_weight) {
136 crm_trace("%s (%d) > %s (%d) : weight",
137 node1->details->uname, node1_weight, node2->details->uname,
138 node2_weight);
139 return -1;
140 }
141
142 if (node1_weight < node2_weight) {
143 crm_trace("%s (%d) < %s (%d) : weight",
144 node1->details->uname, node1_weight, node2->details->uname,
145 node2_weight);
146 return 1;
147 }
148
149 crm_trace("%s (%d) == %s (%d) : weight",
150 node1->details->uname, node1_weight, node2->details->uname,
151 node2_weight);
152
153 // If appropriate, compare node utilization
154
155 if (pcmk__str_eq(nw->data_set->placement_strategy, "minimal",
157 goto equal;
158 }
159
160 if (pcmk__str_eq(nw->data_set->placement_strategy, "balanced",
163 if (result < 0) {
164 crm_trace("%s > %s : capacity (%d)",
165 node1->details->uname, node2->details->uname, result);
166 return -1;
167 } else if (result > 0) {
168 crm_trace("%s < %s : capacity (%d)",
169 node1->details->uname, node2->details->uname, result);
170 return 1;
171 }
172 }
173
174 // Compare number of allocated resources
175
176 if (node1->details->num_resources < node2->details->num_resources) {
177 crm_trace("%s (%d) > %s (%d) : resources",
178 node1->details->uname, node1->details->num_resources,
179 node2->details->uname, node2->details->num_resources);
180 return -1;
181
182 } else if (node1->details->num_resources > node2->details->num_resources) {
183 crm_trace("%s (%d) < %s (%d) : resources",
184 node1->details->uname, node1->details->num_resources,
185 node2->details->uname, node2->details->num_resources);
186 return 1;
187 }
188
189 // Check whether one node is already running desired resource
190
191 if (nw->active != NULL) {
192 if (nw->active->details == node1->details) {
193 crm_trace("%s (%d) > %s (%d) : active",
194 node1->details->uname, node1->details->num_resources,
195 node2->details->uname, node2->details->num_resources);
196 return -1;
197 } else if (nw->active->details == node2->details) {
198 crm_trace("%s (%d) < %s (%d) : active",
199 node1->details->uname, node1->details->num_resources,
200 node2->details->uname, node2->details->num_resources);
201 return 1;
202 }
203 }
204
205 // If all else is equal, prefer node with lowest-sorting name
206equal:
207 crm_trace("%s = %s", node1->details->uname, node2->details->uname);
208 return strcmp(node1->details->uname, node2->details->uname);
209}
210
221GList *
222pcmk__sort_nodes(GList *nodes, pe_node_t *active_node,
224{
225 struct node_weight_s nw = { active_node, data_set };
226
227 return g_list_sort_with_data(nodes, compare_nodes, &nw);
228}
229
239bool
240pcmk__any_node_available(GHashTable *nodes)
241{
242 GHashTableIter iter;
243 pe_node_t *node = NULL;
244
245 if (nodes == NULL) {
246 return false;
247 }
248 g_hash_table_iter_init(&iter, nodes);
249 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
250 if ((node->weight >= 0) && pcmk__node_available(node)) {
251 return true;
252 }
253 }
254 return false;
255}
256
263void
265{
266 int base_health = 0;
267 enum pcmk__health_strategy strategy;
268 const char *strategy_str = pe_pref(data_set->config_hash,
270
271 strategy = pcmk__parse_health_strategy(strategy_str);
272 if (strategy == pcmk__health_strategy_none) {
273 return;
274 }
275 crm_info("Applying node health strategy '%s'", strategy_str);
276
277 // The progressive strategy can use a base health score
278 if (strategy == pcmk__health_strategy_progressive) {
279 base_health = pe__health_score(PCMK__OPT_NODE_HEALTH_BASE, data_set);
280 }
281
282 for (GList *iter = data_set->nodes; iter != NULL; iter = iter->next) {
283 pe_node_t *node = (pe_node_t *) iter->data;
284 int health = pe__sum_node_health_scores(node, base_health);
285
286 // An overall health score of 0 has no effect
287 if (health == 0) {
288 continue;
289 }
290 crm_info("Node %s overall system health is %d",
291 node->details->uname, health);
292
293 // Use node health as a location score for each resource on the node
294 for (GList *r = data_set->resources; r != NULL; r = r->next) {
295 pe_resource_t *rsc = (pe_resource_t *) r->data;
296
297 bool constrain = true;
298
299 if (health < 0) {
300 /* Negative health scores do not apply to resources with
301 * allow-unhealthy-nodes=true.
302 */
303 constrain = !crm_is_true(g_hash_table_lookup(rsc->meta,
305 }
306 if (constrain) {
307 pcmk__new_location(strategy_str, rsc, health, NULL, node,
308 data_set);
309 } else {
310 pe_rsc_trace(rsc, "%s is immune from health ban on %s",
311 rsc->id, node->details->uname);
312 }
313 }
314 }
315}
gboolean crm_is_true(const char *s)
Definition: strings.c:416
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:305
char data[0]
Definition: cpg.c:10
#define INFINITY
Definition: crm.h:99
pcmk__health_strategy
@ pcmk__health_strategy_progressive
@ pcmk__health_strategy_none
enum pcmk__health_strategy pcmk__parse_health_strategy(const char *value)
Definition: health.c:41
G_GNUC_INTERNAL pe__location_t * pcmk__new_location(const char *id, pe_resource_t *rsc, int node_weight, const char *discover_mode, pe_node_t *foo_node, pe_working_set_t *data_set)
G_GNUC_INTERNAL int pcmk__compare_node_capacities(const pe_node_t *node1, const pe_node_t *node2)
#define crm_info(fmt, args...)
Definition: logging.h:361
#define crm_trace(fmt, args...)
Definition: logging.h:364
Resource agent executor.
pe_working_set_t * data_set
#define PCMK__OPT_NODE_HEALTH_STRATEGY
#define PCMK__META_ALLOW_UNHEALTHY_NODES
#define PCMK__OPT_NODE_HEALTH_BASE
High Level API.
pcmk__action_result_t result
Definition: pcmk_fence.c:34
GHashTable * pcmk__copy_node_table(GHashTable *nodes)
bool pcmk__any_node_available(GHashTable *nodes)
void pcmk__apply_node_health(pe_working_set_t *data_set)
GList * pcmk__copy_node_list(const GList *list, bool reset)
GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
bool pcmk__node_available(const pe_node_t *node)
int pe__sum_node_health_scores(const pe_node_t *node, int base_health)
Definition: pe_health.c:94
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:22
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:141
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
@ pcmk__str_casei
int weight
Definition: pe_types.h:249
struct pe_node_shared_s * details
Definition: pe_types.h:252
gboolean shutdown
Definition: pe_types.h:226
const char * id
Definition: pe_types.h:215
gboolean online
Definition: pe_types.h:220
const char * uname
Definition: pe_types.h:216
gboolean standby
Definition: pe_types.h:221
gboolean unclean
Definition: pe_types.h:224
gboolean maintenance
Definition: pe_types.h:229
GHashTable * meta
Definition: pe_types.h:387
char * id
Definition: pe_types.h:336
GHashTable * config_hash
Definition: pe_types.h:158
GList * resources
Definition: pe_types.h:165
GList * nodes
Definition: pe_types.h:164