pacemaker 2.1.5-a3f44794f94
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
30bool
31pcmk__node_available(const pe_node_t *node, bool consider_score,
32 bool consider_guest)
33{
34 if ((node == NULL) || (node->details == NULL) || !node->details->online
35 || node->details->shutdown || node->details->unclean
36 || node->details->standby || node->details->maintenance) {
37 return false;
38 }
39
40 if (consider_score && (node->weight < 0)) {
41 return false;
42 }
43
44 // @TODO Go through all callers to see which should set consider_guest
45 if (consider_guest && pe__is_guest_node(node)) {
47
48 if (guest->fns->location(guest, NULL, FALSE) == NULL) {
49 return false;
50 }
51 }
52
53 return true;
54}
55
64GHashTable *
65pcmk__copy_node_table(GHashTable *nodes)
66{
67 GHashTable *new_table = NULL;
68 GHashTableIter iter;
69 pe_node_t *node = NULL;
70
71 if (nodes == NULL) {
72 return NULL;
73 }
74 new_table = pcmk__strkey_table(NULL, free);
75 g_hash_table_iter_init(&iter, nodes);
76 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
77 pe_node_t *new_node = pe__copy_node(node);
78
79 g_hash_table_insert(new_table, (gpointer) new_node->details->id,
80 new_node);
81 }
82 return new_table;
83}
84
94GList *
95pcmk__copy_node_list(const GList *list, bool reset)
96{
97 GList *result = NULL;
98
99 for (const GList *gIter = list; gIter != NULL; gIter = gIter->next) {
100 pe_node_t *new_node = NULL;
101 pe_node_t *this_node = (pe_node_t *) gIter->data;
102
103 new_node = pe__copy_node(this_node);
104 if (reset) {
105 new_node->weight = 0;
106 }
107 result = g_list_prepend(result, new_node);
108 }
109 return result;
110}
111
126static gint
127compare_nodes(gconstpointer a, gconstpointer b, gpointer data)
128{
129 const pe_node_t *node1 = (const pe_node_t *) a;
130 const pe_node_t *node2 = (const pe_node_t *) b;
131 pe_node_t *active = (pe_node_t *) data;
132
133 int node1_weight = 0;
134 int node2_weight = 0;
135
136 int result = 0;
137
138 if (a == NULL) {
139 return 1;
140 }
141 if (b == NULL) {
142 return -1;
143 }
144
145 // Compare node weights
146
147 node1_weight = pcmk__node_available(node1, false, false)? node1->weight : -INFINITY;
148 node2_weight = pcmk__node_available(node2, false, false)? node2->weight : -INFINITY;
149
150 if (node1_weight > node2_weight) {
151 crm_trace("%s (%d) > %s (%d) : weight",
152 pe__node_name(node1), node1_weight, pe__node_name(node2),
153 node2_weight);
154 return -1;
155 }
156
157 if (node1_weight < node2_weight) {
158 crm_trace("%s (%d) < %s (%d) : weight",
159 pe__node_name(node1), node1_weight, pe__node_name(node2),
160 node2_weight);
161 return 1;
162 }
163
164 crm_trace("%s (%d) == %s (%d) : weight",
165 pe__node_name(node1), node1_weight, pe__node_name(node2),
166 node2_weight);
167
168 // If appropriate, compare node utilization
169
170 if (pcmk__str_eq(node1->details->data_set->placement_strategy, "minimal",
172 goto equal;
173 }
174
175 if (pcmk__str_eq(node1->details->data_set->placement_strategy, "balanced",
178 if (result < 0) {
179 crm_trace("%s > %s : capacity (%d)",
180 pe__node_name(node1), pe__node_name(node2), result);
181 return -1;
182 } else if (result > 0) {
183 crm_trace("%s < %s : capacity (%d)",
184 pe__node_name(node1), pe__node_name(node2), result);
185 return 1;
186 }
187 }
188
189 // Compare number of allocated resources
190
192 crm_trace("%s (%d) > %s (%d) : resources",
193 pe__node_name(node1), node1->details->num_resources,
194 pe__node_name(node2), node2->details->num_resources);
195 return -1;
196
198 crm_trace("%s (%d) < %s (%d) : resources",
199 pe__node_name(node1), node1->details->num_resources,
200 pe__node_name(node2), node2->details->num_resources);
201 return 1;
202 }
203
204 // Check whether one node is already running desired resource
205
206 if (active != NULL) {
207 if (active->details == node1->details) {
208 crm_trace("%s (%d) > %s (%d) : active",
209 pe__node_name(node1), node1->details->num_resources,
210 pe__node_name(node2), node2->details->num_resources);
211 return -1;
212 } else if (active->details == node2->details) {
213 crm_trace("%s (%d) < %s (%d) : active",
214 pe__node_name(node1), node1->details->num_resources,
215 pe__node_name(node2), node2->details->num_resources);
216 return 1;
217 }
218 }
219
220 // If all else is equal, prefer node with lowest-sorting name
221equal:
222 crm_trace("%s = %s", pe__node_name(node1), pe__node_name(node2));
223 return strcmp(node1->details->uname, node2->details->uname);
224}
225
236GList *
237pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
238{
239 return g_list_sort_with_data(nodes, compare_nodes, active_node);
240}
241
251bool
252pcmk__any_node_available(GHashTable *nodes)
253{
254 GHashTableIter iter;
255 pe_node_t *node = NULL;
256
257 if (nodes == NULL) {
258 return false;
259 }
260 g_hash_table_iter_init(&iter, nodes);
261 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
262 if (pcmk__node_available(node, true, false)) {
263 return true;
264 }
265 }
266 return false;
267}
268
275void
277{
278 int base_health = 0;
279 enum pcmk__health_strategy strategy;
280 const char *strategy_str = pe_pref(data_set->config_hash,
282
283 strategy = pcmk__parse_health_strategy(strategy_str);
284 if (strategy == pcmk__health_strategy_none) {
285 return;
286 }
287 crm_info("Applying node health strategy '%s'", strategy_str);
288
289 // The progressive strategy can use a base health score
290 if (strategy == pcmk__health_strategy_progressive) {
291 base_health = pe__health_score(PCMK__OPT_NODE_HEALTH_BASE, data_set);
292 }
293
294 for (GList *iter = data_set->nodes; iter != NULL; iter = iter->next) {
295 pe_node_t *node = (pe_node_t *) iter->data;
296 int health = pe__sum_node_health_scores(node, base_health);
297
298 // An overall health score of 0 has no effect
299 if (health == 0) {
300 continue;
301 }
302 crm_info("Overall system health of %s is %d",
303 pe__node_name(node), health);
304
305 // Use node health as a location score for each resource on the node
306 for (GList *r = data_set->resources; r != NULL; r = r->next) {
307 pe_resource_t *rsc = (pe_resource_t *) r->data;
308
309 bool constrain = true;
310
311 if (health < 0) {
312 /* Negative health scores do not apply to resources with
313 * allow-unhealthy-nodes=true.
314 */
315 constrain = !crm_is_true(g_hash_table_lookup(rsc->meta,
317 }
318 if (constrain) {
319 pcmk__new_location(strategy_str, rsc, health, NULL, node,
320 data_set);
321 } else {
322 pe_rsc_trace(rsc, "%s is immune from health ban on %s",
323 rsc->id, pe__node_name(node));
324 }
325 }
326 }
327}
328
339pe_node_t *
341{
342 GHashTable *allowed_nodes = NULL;
343
344 if ((rsc == NULL) || (node == NULL)) {
345 return NULL;
346 } else if (rsc->parent == NULL) {
347 allowed_nodes = rsc->allowed_nodes;
348 } else {
349 allowed_nodes = rsc->parent->allowed_nodes;
350 }
351 return pe_hash_table_lookup(allowed_nodes, node->details->id);
352}
gboolean crm_is_true(const char *s)
Definition: strings.c:416
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:307
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:362
#define crm_trace(fmt, args...)
Definition: logging.h:365
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:35
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)
bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
pe_node_t * pcmk__top_allowed_node(const pe_resource_t *rsc, const pe_node_t *node)
pe_node_t node1
pe_node_t node2
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:47
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
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
pe_working_set_t * data_set
Cluster that this node is part of.
Definition: pe_types.h:245
gboolean standby
Definition: pe_types.h:221
pe_resource_t * remote_rsc
Definition: pe_types.h:237
gboolean unclean
Definition: pe_types.h:224
gboolean maintenance
Definition: pe_types.h:229
GHashTable * meta
Definition: pe_types.h:380
pe_resource_t * container
Definition: pe_types.h:387
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
pe_resource_t * parent
Definition: pe_types.h:336
resource_object_functions_t * fns
Definition: pe_types.h:340
const char * placement_strategy
Definition: pe_types.h:151
GHashTable * config_hash
Definition: pe_types.h:158
GList * resources
Definition: pe_types.h:165
GList * nodes
Definition: pe_types.h:164
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55