This source file includes following definitions.
- pcmk__node_available
- pcmk__copy_node_table
- destroy_node_tables
- pcmk__copy_node_tables
- pcmk__restore_node_tables
- pcmk__copy_node_list
- compare_nodes
- pcmk__sort_nodes
- pcmk__any_node_available
- pcmk__apply_node_health
- pcmk__top_allowed_node
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/common/xml.h>
12 #include <crm/common/xml_internal.h>
13 #include <pacemaker-internal.h>
14 #include <pacemaker.h>
15 #include "libpacemaker_private.h"
16
17
18
19
20
21
22
23
24
25
26
27
28
29 bool
30 pcmk__node_available(const pcmk_node_t *node, bool consider_score,
31 bool consider_guest)
32 {
33 if ((node == NULL) || (node->details == NULL) || !node->details->online
34 || node->details->shutdown || node->details->unclean
35 || node->details->standby || node->details->maintenance) {
36 return false;
37 }
38
39 if (consider_score && (node->weight < 0)) {
40 return false;
41 }
42
43
44 if (consider_guest && pcmk__is_guest_or_bundle_node(node)) {
45 pcmk_resource_t *guest = node->details->remote_rsc->container;
46
47 if (guest->fns->location(guest, NULL, FALSE) == NULL) {
48 return false;
49 }
50 }
51
52 return true;
53 }
54
55
56
57
58
59
60
61
62
63 GHashTable *
64 pcmk__copy_node_table(GHashTable *nodes)
65 {
66 GHashTable *new_table = NULL;
67 GHashTableIter iter;
68 pcmk_node_t *node = NULL;
69
70 if (nodes == NULL) {
71 return NULL;
72 }
73 new_table = pcmk__strkey_table(NULL, free);
74 g_hash_table_iter_init(&iter, nodes);
75 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
76 pcmk_node_t *new_node = pe__copy_node(node);
77
78 g_hash_table_insert(new_table, (gpointer) new_node->details->id,
79 new_node);
80 }
81 return new_table;
82 }
83
84
85
86
87
88
89
90
91
92 static void
93 destroy_node_tables(gpointer data)
94 {
95 g_hash_table_destroy((GHashTable *) data);
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 void
114 pcmk__copy_node_tables(const pcmk_resource_t *rsc, GHashTable **copy)
115 {
116 CRM_ASSERT((rsc != NULL) && (copy != NULL));
117
118 if (*copy == NULL) {
119 *copy = pcmk__strkey_table(NULL, destroy_node_tables);
120 }
121
122 g_hash_table_insert(*copy, rsc->id,
123 pcmk__copy_node_table(rsc->allowed_nodes));
124
125 for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) {
126 pcmk__copy_node_tables((const pcmk_resource_t *) iter->data, copy);
127 }
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 void
145 pcmk__restore_node_tables(pcmk_resource_t *rsc, GHashTable *backup)
146 {
147 CRM_ASSERT((rsc != NULL) && (backup != NULL));
148
149 g_hash_table_destroy(rsc->allowed_nodes);
150
151
152 rsc->allowed_nodes = g_hash_table_lookup(backup, rsc->id);
153 rsc->allowed_nodes = pcmk__copy_node_table(rsc->allowed_nodes);
154
155 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
156 pcmk__restore_node_tables((pcmk_resource_t *) iter->data, backup);
157 }
158 }
159
160
161
162
163
164
165
166
167
168
169 GList *
170 pcmk__copy_node_list(const GList *list, bool reset)
171 {
172 GList *result = NULL;
173
174 for (const GList *iter = list; iter != NULL; iter = iter->next) {
175 pcmk_node_t *new_node = NULL;
176 pcmk_node_t *this_node = iter->data;
177
178 new_node = pe__copy_node(this_node);
179 if (reset) {
180 new_node->weight = 0;
181 }
182 result = g_list_prepend(result, new_node);
183 }
184 return result;
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201 static gint
202 compare_nodes(gconstpointer a, gconstpointer b, gpointer data)
203 {
204 const pcmk_node_t *node1 = (const pcmk_node_t *) a;
205 const pcmk_node_t *node2 = (const pcmk_node_t *) b;
206 const pcmk_node_t *preferred = (const pcmk_node_t *) data;
207
208 int node1_score = -PCMK_SCORE_INFINITY;
209 int node2_score = -PCMK_SCORE_INFINITY;
210
211 int result = 0;
212
213 if (a == NULL) {
214 return 1;
215 }
216 if (b == NULL) {
217 return -1;
218 }
219
220
221
222 if (pcmk__node_available(node1, false, false)) {
223 node1_score = node1->weight;
224 }
225 if (pcmk__node_available(node2, false, false)) {
226 node2_score = node2->weight;
227 }
228
229 if (node1_score > node2_score) {
230 crm_trace("%s before %s (score %d > %d)",
231 pcmk__node_name(node1), pcmk__node_name(node2),
232 node1_score, node2_score);
233 return -1;
234 }
235
236 if (node1_score < node2_score) {
237 crm_trace("%s after %s (score %d < %d)",
238 pcmk__node_name(node1), pcmk__node_name(node2),
239 node1_score, node2_score);
240 return 1;
241 }
242
243
244
245 if (pcmk__str_eq(node1->details->data_set->placement_strategy,
246 PCMK_VALUE_MINIMAL, pcmk__str_casei)) {
247 goto equal;
248 }
249
250 if (pcmk__str_eq(node1->details->data_set->placement_strategy,
251 PCMK_VALUE_BALANCED, pcmk__str_casei)) {
252
253 result = pcmk__compare_node_capacities(node1, node2);
254 if (result < 0) {
255 crm_trace("%s before %s (greater capacity by %d attributes)",
256 pcmk__node_name(node1), pcmk__node_name(node2),
257 result * -1);
258 return -1;
259 } else if (result > 0) {
260 crm_trace("%s after %s (lower capacity by %d attributes)",
261 pcmk__node_name(node1), pcmk__node_name(node2), result);
262 return 1;
263 }
264 }
265
266
267
268 if (node1->details->num_resources < node2->details->num_resources) {
269 crm_trace("%s before %s (%d resources < %d)",
270 pcmk__node_name(node1), pcmk__node_name(node2),
271 node1->details->num_resources, node2->details->num_resources);
272 return -1;
273
274 } else if (node1->details->num_resources > node2->details->num_resources) {
275 crm_trace("%s after %s (%d resources > %d)",
276 pcmk__node_name(node1), pcmk__node_name(node2),
277 node1->details->num_resources, node2->details->num_resources);
278 return 1;
279 }
280
281
282
283 if (preferred != NULL) {
284 if (pcmk__same_node(preferred, node1)) {
285 crm_trace("%s before %s (preferred node)",
286 pcmk__node_name(node1), pcmk__node_name(node2));
287 return -1;
288 } else if (pcmk__same_node(preferred, node2)) {
289 crm_trace("%s after %s (not preferred node)",
290 pcmk__node_name(node1), pcmk__node_name(node2));
291 return 1;
292 }
293 }
294
295
296 equal:
297 result = strcmp(node1->details->uname, node2->details->uname);
298 if (result < 0) {
299 crm_trace("%s before %s (name)",
300 pcmk__node_name(node1), pcmk__node_name(node2));
301 return -1;
302 } else if (result > 0) {
303 crm_trace("%s after %s (name)",
304 pcmk__node_name(node1), pcmk__node_name(node2));
305 return 1;
306 }
307
308 crm_trace("%s == %s", pcmk__node_name(node1), pcmk__node_name(node2));
309 return 0;
310 }
311
312
313
314
315
316
317
318
319
320
321 GList *
322 pcmk__sort_nodes(GList *nodes, pcmk_node_t *active_node)
323 {
324 return g_list_sort_with_data(nodes, compare_nodes, active_node);
325 }
326
327
328
329
330
331
332
333
334
335
336 bool
337 pcmk__any_node_available(GHashTable *nodes)
338 {
339 GHashTableIter iter;
340 const pcmk_node_t *node = NULL;
341
342 if (nodes == NULL) {
343 return false;
344 }
345 g_hash_table_iter_init(&iter, nodes);
346 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
347 if (pcmk__node_available(node, true, false)) {
348 return true;
349 }
350 }
351 return false;
352 }
353
354
355
356
357
358
359
360 void
361 pcmk__apply_node_health(pcmk_scheduler_t *scheduler)
362 {
363 int base_health = 0;
364 enum pcmk__health_strategy strategy;
365 const char *strategy_str =
366 pcmk__cluster_option(scheduler->config_hash,
367 PCMK_OPT_NODE_HEALTH_STRATEGY);
368
369 strategy = pcmk__parse_health_strategy(strategy_str);
370 if (strategy == pcmk__health_strategy_none) {
371 return;
372 }
373 crm_info("Applying node health strategy '%s'", strategy_str);
374
375
376 if (strategy == pcmk__health_strategy_progressive) {
377 base_health = pe__health_score(PCMK_OPT_NODE_HEALTH_BASE, scheduler);
378 }
379
380 for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
381 pcmk_node_t *node = (pcmk_node_t *) iter->data;
382 int health = pe__sum_node_health_scores(node, base_health);
383
384
385 if (health == 0) {
386 continue;
387 }
388 crm_info("Overall system health of %s is %d",
389 pcmk__node_name(node), health);
390
391
392 for (GList *r = scheduler->resources; r != NULL; r = r->next) {
393 pcmk_resource_t *rsc = (pcmk_resource_t *) r->data;
394
395 bool constrain = true;
396
397 if (health < 0) {
398
399
400
401 constrain = !crm_is_true(g_hash_table_lookup(rsc->meta,
402 PCMK_META_ALLOW_UNHEALTHY_NODES));
403 }
404 if (constrain) {
405 pcmk__new_location(strategy_str, rsc, health, NULL, node);
406 } else {
407 pcmk__rsc_trace(rsc, "%s is immune from health ban on %s",
408 rsc->id, pcmk__node_name(node));
409 }
410 }
411 }
412 }
413
414
415
416
417
418
419
420
421
422
423
424 pcmk_node_t *
425 pcmk__top_allowed_node(const pcmk_resource_t *rsc, const pcmk_node_t *node)
426 {
427 GHashTable *allowed_nodes = NULL;
428
429 if ((rsc == NULL) || (node == NULL)) {
430 return NULL;
431 } else if (rsc->parent == NULL) {
432 allowed_nodes = rsc->allowed_nodes;
433 } else {
434 allowed_nodes = rsc->parent->allowed_nodes;
435 }
436 return g_hash_table_lookup(allowed_nodes, node->details->id);
437 }