pacemaker  2.1.4-dc6eb4362
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 
27 bool
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 
44 GHashTable *
45 pcmk__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 
74 GList *
75 pcmk__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 
92 struct node_weight_s {
93  pe_node_t *active;
95 };
96 
111 static gint
112 compare_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",
156  pcmk__str_casei)) {
157  goto equal;
158  }
159 
160  if (pcmk__str_eq(nw->data_set->placement_strategy, "balanced",
161  pcmk__str_casei)) {
162  result = pcmk__compare_node_capacities(node1, node2);
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
206 equal:
207  crm_trace("%s = %s", node1->details->uname, node2->details->uname);
208  return strcmp(node1->details->uname, node2->details->uname);
209 }
210 
221 GList *
222 pcmk__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 
239 bool
240 pcmk__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 
263 void
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 }
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:99
GHashTable * meta
Definition: pe_types.h:387
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:141
Resource agent executor.
High Level API.
const char * pe_pref(GHashTable *options, const char *name)
Definition: common.c:305
void pcmk__apply_node_health(pe_working_set_t *data_set)
enum pcmk__health_strategy pcmk__parse_health_strategy(const char *value)
Definition: health.c:41
GList * resources
Definition: pe_types.h:165
bool pcmk__any_node_available(GHashTable *nodes)
GList * nodes
Definition: pe_types.h:164
int weight
Definition: pe_types.h:249
#define PCMK__OPT_NODE_HEALTH_BASE
GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
#define crm_trace(fmt, args...)
Definition: logging.h:364
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
gboolean standby
Definition: pe_types.h:221
#define PCMK__OPT_NODE_HEALTH_STRATEGY
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
bool pcmk__node_available(const pe_node_t *node)
pcmk__action_result_t result
Definition: pcmk_fence.c:34
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:22
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:361
gboolean online
Definition: pe_types.h:220
char * id
Definition: pe_types.h:336