pacemaker  2.1.5-b7adf64e51
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>
16 #include "libpacemaker_private.h"
17 
30 bool
31 pcmk__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)) {
46  pe_resource_t *guest = node->details->remote_rsc->container;
47 
48  if (guest->fns->location(guest, NULL, FALSE) == NULL) {
49  return false;
50  }
51  }
52 
53  return true;
54 }
55 
64 GHashTable *
65 pcmk__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 
94 GList *
95 pcmk__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 
126 static gint
127 compare_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",
171  pcmk__str_casei)) {
172  goto equal;
173  }
174 
175  if (pcmk__str_eq(node1->details->data_set->placement_strategy, "balanced",
176  pcmk__str_casei)) {
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
221 equal:
222  crm_trace("%s = %s", pe__node_name(node1), pe__node_name(node2));
223  return strcmp(node1->details->uname, node2->details->uname);
224 }
225 
236 GList *
237 pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
238 {
239  return g_list_sort_with_data(nodes, compare_nodes, active_node);
240 }
241 
251 bool
252 pcmk__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 
275 void
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 
339 pe_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 }
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:99
pe_node_t * pcmk__top_allowed_node(const pe_resource_t *rsc, const pe_node_t *node)
pe_resource_t * container
Definition: pe_types.h:387
pe_resource_t * remote_rsc
Definition: pe_types.h:237
GHashTable * meta
Definition: pe_types.h:380
resource_object_functions_t * fns
Definition: pe_types.h:340
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
Resource agent executor.
High Level API.
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:307
void pcmk__apply_node_health(pe_working_set_t *data_set)
GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
enum pcmk__health_strategy pcmk__parse_health_strategy(const char *value)
Definition: health.c:41
pe_working_set_t * data_set
Cluster that this node is part of.
Definition: pe_types.h:245
GList * resources
Definition: pe_types.h:165
bool pcmk__any_node_available(GHashTable *nodes)
GList * nodes
Definition: pe_types.h:164
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55
int weight
Definition: pe_types.h:249
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
#define PCMK__OPT_NODE_HEALTH_BASE
#define crm_trace(fmt, args...)
Definition: logging.h:365
GList * pcmk__copy_node_list(const GList *list, bool reset)
struct pe_node_shared_s * details
Definition: pe_types.h:252
const char * uname
Definition: pe_types.h:216
pe_working_set_t * data_set
GHashTable * config_hash
Definition: pe_types.h:158
pe_node_t node1
gboolean standby
Definition: pe_types.h:221
const char * placement_strategy
Definition: pe_types.h:151
#define PCMK__OPT_NODE_HEALTH_STRATEGY
pe_node_t node2
const char * id
Definition: pe_types.h:215
#define PCMK__META_ALLOW_UNHEALTHY_NODES
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)
GHashTable * pcmk__copy_node_table(GHashTable *nodes)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
pcmk__action_result_t result
Definition: pcmk_fence.c:35
G_GNUC_INTERNAL int pcmk__compare_node_capacities(const pe_node_t *node1, const pe_node_t *node2)
pcmk__health_strategy
gboolean shutdown
Definition: pe_types.h:226
gboolean maintenance
Definition: pe_types.h:229
gboolean crm_is_true(const char *s)
Definition: strings.c:416
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
int pe__sum_node_health_scores(const pe_node_t *node, int base_health)
Definition: pe_health.c:94
gboolean unclean
Definition: pe_types.h:224
#define crm_info(fmt, args...)
Definition: logging.h:362
gboolean online
Definition: pe_types.h:220
pe_resource_t * parent
Definition: pe_types.h:336
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375