pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmk_sched_promotable.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2021 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 
12 #include <crm/msg_xml.h>
13 #include <pacemaker-internal.h>
14 
15 #define VARIANT_CLONE 1
16 #include <lib/pengine/variant.h>
17 
18 extern gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
19 
20 extern bool pcmk__is_daemon;
21 
22 static void
23 child_promoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
24  pe_resource_t * rsc, pe_resource_t * child, pe_resource_t * last,
25  pe_working_set_t * data_set)
26 {
27  if (child == NULL) {
28  if (clone_data->ordered && last != NULL) {
29  pe_rsc_trace(rsc, "Ordered version (last node)");
30  /* last child promote before promoted started */
31  new_rsc_order(last, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set);
32  }
33  return;
34  }
35 
36  /* child promote before global promoted */
37  new_rsc_order(child, RSC_PROMOTE, rsc, RSC_PROMOTED, type, data_set);
38 
39  /* global promote before child promote */
40  new_rsc_order(rsc, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set);
41 
42  if (clone_data->ordered) {
43  pe_rsc_trace(rsc, "Ordered version");
44  if (last == NULL) {
45  /* global promote before first child promote */
46  last = rsc;
47 
48  }
49  /* else: child/child relative promote */
50  order_start_start(last, child, type);
51  new_rsc_order(last, RSC_PROMOTE, child, RSC_PROMOTE, type, data_set);
52 
53  } else {
54  pe_rsc_trace(rsc, "Un-ordered version");
55  }
56 }
57 
58 static void
59 child_demoting_constraints(clone_variant_data_t * clone_data, enum pe_ordering type,
60  pe_resource_t * rsc, pe_resource_t * child, pe_resource_t * last,
61  pe_working_set_t * data_set)
62 {
63  if (child == NULL) {
64  if (clone_data->ordered && last != NULL) {
65  pe_rsc_trace(rsc, "Ordered version (last node)");
66  /* global demote before first child demote */
67  new_rsc_order(rsc, RSC_DEMOTE, last, RSC_DEMOTE, pe_order_optional, data_set);
68  }
69  return;
70  }
71 
72  /* child demote before global demoted */
74 
75  /* global demote before child demote */
77 
78  if (clone_data->ordered && last != NULL) {
79  pe_rsc_trace(rsc, "Ordered version");
80 
81  /* child/child relative demote */
82  new_rsc_order(child, RSC_DEMOTE, last, RSC_DEMOTE, type, data_set);
83 
84  } else if (clone_data->ordered) {
85  pe_rsc_trace(rsc, "Ordered version (1st node)");
86  /* first child stop before global stopped */
87  new_rsc_order(child, RSC_DEMOTE, rsc, RSC_DEMOTED, type, data_set);
88 
89  } else {
90  pe_rsc_trace(rsc, "Un-ordered version");
91  }
92 }
93 
94 static void
95 check_promotable_actions(pe_resource_t *rsc, gboolean *demoting,
96  gboolean *promoting)
97 {
98  GList *gIter = NULL;
99 
100  if (rsc->children) {
101  gIter = rsc->children;
102  for (; gIter != NULL; gIter = gIter->next) {
103  pe_resource_t *child = (pe_resource_t *) gIter->data;
104 
105  check_promotable_actions(child, demoting, promoting);
106  }
107  return;
108  }
109 
110  CRM_ASSERT(demoting != NULL);
111  CRM_ASSERT(promoting != NULL);
112 
113  gIter = rsc->actions;
114  for (; gIter != NULL; gIter = gIter->next) {
115  pe_action_t *action = (pe_action_t *) gIter->data;
116 
117  if (*promoting && *demoting) {
118  return;
119 
120  } else if (pcmk_is_set(action->flags, pe_action_optional)) {
121  continue;
122 
123  } else if (pcmk__str_eq(RSC_DEMOTE, action->task, pcmk__str_casei)) {
124  *demoting = TRUE;
125 
126  } else if (pcmk__str_eq(RSC_PROMOTE, action->task, pcmk__str_casei)) {
127  *promoting = TRUE;
128  }
129  }
130 }
131 
132 static void
133 apply_promoted_location(pe_resource_t *child, GList *location_constraints,
134  pe_node_t *chosen)
135 {
136  CRM_CHECK(child && chosen, return);
137  for (GList *gIter = location_constraints; gIter; gIter = gIter->next) {
138  pe_node_t *cons_node = NULL;
139  pe__location_t *cons = gIter->data;
140 
141  if (cons->role_filter == RSC_ROLE_PROMOTED) {
142  pe_rsc_trace(child, "Applying %s to %s", cons->id, child->id);
143  cons_node = pe_find_node_id(cons->node_list_rh, chosen->details->id);
144  }
145  if (cons_node != NULL) {
146  int new_priority = pe__add_scores(child->priority,
147  cons_node->weight);
148 
149  pe_rsc_trace(child, "\t%s[%s]: %d -> %d (%d)",
150  child->id, cons_node->details->uname, child->priority,
151  new_priority, cons_node->weight);
152  child->priority = new_priority;
153  }
154  }
155 }
156 
157 static pe_node_t *
158 guest_location(pe_node_t *guest_node)
159 {
160  pe_resource_t *guest = guest_node->details->remote_rsc->container;
161 
162  return guest->fns->location(guest, NULL, FALSE);
163 }
164 
165 static pe_node_t *
166 node_to_be_promoted_on(pe_resource_t *rsc)
167 {
168  pe_node_t *node = NULL;
169  pe_node_t *local_node = NULL;
170  pe_resource_t *parent = uber_parent(rsc);
171  clone_variant_data_t *clone_data = NULL;
172 
173 #if 0
174  enum rsc_role_e role = RSC_ROLE_UNKNOWN;
175 
176  role = rsc->fns->state(rsc, FALSE);
177  crm_info("%s role: %s", rsc->id, role2text(role));
178 #endif
179 
180  if (rsc->children) {
181  GList *gIter = rsc->children;
182 
183  for (; gIter != NULL; gIter = gIter->next) {
184  pe_resource_t *child = (pe_resource_t *) gIter->data;
185 
186  if (node_to_be_promoted_on(child) == NULL) {
187  pe_rsc_trace(rsc, "Child %s of %s can't be promoted", child->id, rsc->id);
188  return NULL;
189  }
190  }
191  }
192 
193  node = rsc->fns->location(rsc, NULL, FALSE);
194  if (node == NULL) {
195  pe_rsc_trace(rsc, "%s cannot be promoted: not allocated", rsc->id);
196  return NULL;
197 
198  } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
199  if (rsc->fns->state(rsc, TRUE) == RSC_ROLE_PROMOTED) {
200  crm_notice("Forcing unmanaged instance %s to remain promoted on %s",
201  rsc->id, node->details->uname);
202 
203  } else {
204  return NULL;
205  }
206 
207  } else if (rsc->priority < 0) {
208  pe_rsc_trace(rsc, "%s cannot be promoted: preference: %d",
209  rsc->id, rsc->priority);
210  return NULL;
211 
212  } else if (can_run_resources(node) == FALSE) {
213  crm_trace("Node can't run any resources: %s", node->details->uname);
214  return NULL;
215 
216  /* @TODO It's possible this check should be done in can_run_resources()
217  * instead. We should investigate all its callers to figure out whether that
218  * would be a good idea.
219  */
220  } else if (pe__is_guest_node(node) && (guest_location(node) == NULL)) {
221  pe_rsc_trace(rsc, "%s cannot be promoted: guest %s not allocated",
222  rsc->id, node->details->remote_rsc->container->id);
223  return NULL;
224  }
225 
226  get_clone_variant_data(clone_data, parent);
227  local_node = pe_hash_table_lookup(parent->allowed_nodes, node->details->id);
228 
229  if (local_node == NULL) {
230  crm_err("%s cannot run on %s: node not allowed", rsc->id, node->details->uname);
231  return NULL;
232 
233  } else if ((local_node->count < clone_data->promoted_node_max)
234  || !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
235  return local_node;
236 
237  } else {
238  pe_rsc_trace(rsc, "%s cannot be promoted on %s: node full",
239  rsc->id, node->details->uname);
240  }
241 
242  return NULL;
243 }
244 
245 static gint
246 sort_promotable_instance(gconstpointer a, gconstpointer b, gpointer data_set)
247 {
248  int rc;
249  enum rsc_role_e role1 = RSC_ROLE_UNKNOWN;
250  enum rsc_role_e role2 = RSC_ROLE_UNKNOWN;
251 
252  const pe_resource_t *resource1 = (const pe_resource_t *)a;
253  const pe_resource_t *resource2 = (const pe_resource_t *)b;
254 
255  CRM_ASSERT(resource1 != NULL);
256  CRM_ASSERT(resource2 != NULL);
257 
258  role1 = resource1->fns->state(resource1, TRUE);
259  role2 = resource2->fns->state(resource2, TRUE);
260 
261  rc = sort_rsc_index(a, b);
262  if (rc != 0) {
263  crm_trace("%s %c %s (index)", resource1->id, rc < 0 ? '<' : '>', resource2->id);
264  return rc;
265  }
266 
267  if (role1 > role2) {
268  crm_trace("%s %c %s (role)", resource1->id, '<', resource2->id);
269  return -1;
270 
271  } else if (role1 < role2) {
272  crm_trace("%s %c %s (role)", resource1->id, '>', resource2->id);
273  return 1;
274  }
275 
276  return sort_clone_instance(a, b, data_set);
277 }
278 
279 static void
280 promotion_order(pe_resource_t *rsc, pe_working_set_t *data_set)
281 {
282  GList *gIter = NULL;
283  pe_node_t *node = NULL;
284  pe_node_t *chosen = NULL;
285  clone_variant_data_t *clone_data = NULL;
286  char score[33];
287  size_t len = sizeof(score);
288 
289  get_clone_variant_data(clone_data, rsc);
290 
291  if (clone_data->added_promoted_constraints) {
292  return;
293  }
294  clone_data->added_promoted_constraints = true;
295  pe_rsc_trace(rsc, "Merging weights for %s", rsc->id);
297 
298  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
299  pe_resource_t *child = (pe_resource_t *) gIter->data;
300 
301  pe_rsc_trace(rsc, "Sort index: %s = %d", child->id, child->sort_index);
302  }
303  pe__show_node_weights(true, rsc, "Before", rsc->allowed_nodes, data_set);
304 
305  gIter = rsc->children;
306  for (; gIter != NULL; gIter = gIter->next) {
307  pe_resource_t *child = (pe_resource_t *) gIter->data;
308 
309  chosen = child->fns->location(child, NULL, FALSE);
310  if (chosen == NULL || child->sort_index < 0) {
311  pe_rsc_trace(rsc, "Skipping %s", child->id);
312  continue;
313  }
314 
315  node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
316  CRM_ASSERT(node != NULL);
317  // Add promotion preferences and rsc_location scores when role=Promoted
318  score2char_stack(child->sort_index, score, len);
319  pe_rsc_trace(rsc, "Adding %s to %s from %s", score,
320  node->details->uname, child->id);
321  node->weight = pe__add_scores(child->sort_index, node->weight);
322  }
323 
324  pe__show_node_weights(true, rsc, "Middle", rsc->allowed_nodes, data_set);
325 
326  gIter = rsc->rsc_cons;
327  for (; gIter != NULL; gIter = gIter->next) {
328  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
329 
330  /* (Re-)add location preferences of resources that a promoted instance
331  * should/must be colocated with.
332  */
333  if (constraint->role_lh == RSC_ROLE_PROMOTED) {
334  enum pe_weights flags = constraint->score == INFINITY ? 0 : pe_weights_rollback;
335 
336  pe_rsc_trace(rsc, "RHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id,
337  constraint->score);
338  rsc->allowed_nodes =
339  constraint->rsc_rh->cmds->merge_weights(constraint->rsc_rh, rsc->id,
340  rsc->allowed_nodes,
341  constraint->node_attribute,
342  (float)constraint->score / INFINITY, flags);
343  }
344  }
345 
346  gIter = rsc->rsc_cons_lhs;
347  for (; gIter != NULL; gIter = gIter->next) {
348  pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
349 
350  if (!pcmk__colocation_has_influence(constraint, NULL)) {
351  continue;
352  }
353 
354  /* (Re-)add location preferences of resources that wish to be colocated
355  * with a promoted instance.
356  */
357  if (constraint->role_rh == RSC_ROLE_PROMOTED) {
358  pe_rsc_trace(rsc, "LHS: %s with %s: %d", constraint->rsc_lh->id, constraint->rsc_rh->id,
359  constraint->score);
360  rsc->allowed_nodes =
361  constraint->rsc_lh->cmds->merge_weights(constraint->rsc_lh, rsc->id,
362  rsc->allowed_nodes,
363  constraint->node_attribute,
364  (float)constraint->score / INFINITY,
367  }
368  }
369 
370  gIter = rsc->rsc_tickets;
371  for (; gIter != NULL; gIter = gIter->next) {
372  rsc_ticket_t *rsc_ticket = (rsc_ticket_t *) gIter->data;
373 
374  if ((rsc_ticket->role_lh == RSC_ROLE_PROMOTED)
375  && (rsc_ticket->ticket->granted == FALSE || rsc_ticket->ticket->standby)) {
376  resource_location(rsc, NULL, -INFINITY, "__stateful_without_ticket__", data_set);
377  }
378  }
379 
380  pe__show_node_weights(true, rsc, "After", rsc->allowed_nodes, data_set);
381 
382  /* write them back and sort */
383 
384  gIter = rsc->children;
385  for (; gIter != NULL; gIter = gIter->next) {
386  pe_resource_t *child = (pe_resource_t *) gIter->data;
387 
388  chosen = child->fns->location(child, NULL, FALSE);
389  if (!pcmk_is_set(child->flags, pe_rsc_managed)
390  && (child->next_role == RSC_ROLE_PROMOTED)) {
391  child->sort_index = INFINITY;
392 
393  } else if (chosen == NULL || child->sort_index < 0) {
394  pe_rsc_trace(rsc, "%s: %d", child->id, child->sort_index);
395 
396  } else {
397  node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes, chosen->details->id);
398  CRM_ASSERT(node != NULL);
399 
400  child->sort_index = node->weight;
401  }
402  pe_rsc_trace(rsc, "Set sort index: %s = %d", child->id, child->sort_index);
403  }
404 
405  rsc->children = g_list_sort_with_data(rsc->children,
406  sort_promotable_instance, data_set);
408 }
409 
410 static gboolean
411 filter_anonymous_instance(pe_resource_t *rsc, const pe_node_t *node)
412 {
413  GList *rIter = NULL;
414  char *key = clone_strip(rsc->id);
415  pe_resource_t *parent = uber_parent(rsc);
416 
417  for (rIter = parent->children; rIter; rIter = rIter->next) {
418  /* If there is an active instance on the node, only it receives the
419  * promotion score. Use ->find_rsc() in case this is a cloned group.
420  */
421  pe_resource_t *child = rIter->data;
422  pe_resource_t *active = parent->fns->find_rsc(child, key, node, pe_find_clone|pe_find_current);
423 
424  if(rsc == active) {
425  pe_rsc_trace(rsc, "Found %s for %s active on %s: done", active->id, key, node->details->uname);
426  free(key);
427  return TRUE;
428  } else if(active) {
429  pe_rsc_trace(rsc, "Found %s for %s on %s: not %s", active->id, key, node->details->uname, rsc->id);
430  free(key);
431  return FALSE;
432  } else {
433  pe_rsc_trace(rsc, "%s on %s: not active", key, node->details->uname);
434  }
435  }
436 
437  for (rIter = parent->children; rIter; rIter = rIter->next) {
438  pe_resource_t *child = rIter->data;
439 
440  /*
441  * We know it's not running, but any score will still count if
442  * the instance has been probed on $node
443  *
444  * Again use ->find_rsc() because we might be a cloned group
445  * and knowing that other members of the group are known here
446  * implies nothing
447  */
448  rsc = parent->fns->find_rsc(child, key, NULL, pe_find_clone);
449  CRM_LOG_ASSERT(rsc);
450  if(rsc) {
451  pe_rsc_trace(rsc, "Checking %s for %s on %s", rsc->id, key, node->details->uname);
452  if (g_hash_table_lookup(rsc->known_on, node->details->id)) {
453  free(key);
454  return TRUE;
455  }
456  }
457  }
458  free(key);
459  return FALSE;
460 }
461 
462 static const char *
463 lookup_promotion_score(pe_resource_t *rsc, const pe_node_t *node, const char *name)
464 {
465  const char *attr_value = NULL;
466 
467  if (node && name) {
468  char *attr_name = pcmk_promotion_score_name(name);
469 
470  attr_value = pe_node_attribute_calculated(node, attr_name, rsc);
471  free(attr_name);
472  }
473  return attr_value;
474 }
475 
476 static int
477 promotion_score(pe_resource_t *rsc, const pe_node_t *node, int not_set_value)
478 {
479  char *name = rsc->id;
480  const char *attr_value = NULL;
481  int score = not_set_value;
482  pe_node_t *match = NULL;
483 
484  CRM_CHECK(node != NULL, return not_set_value);
485 
486  if (rsc->children) {
487  GList *gIter = rsc->children;
488 
489  for (; gIter != NULL; gIter = gIter->next) {
490  pe_resource_t *child = (pe_resource_t *) gIter->data;
491  int c_score = promotion_score(child, node, not_set_value);
492 
493  if (score == not_set_value) {
494  score = c_score;
495  } else {
496  score += c_score;
497  }
498  }
499  return score;
500  }
501 
502  if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
503  && filter_anonymous_instance(rsc, node)) {
504 
505  pe_rsc_trace(rsc, "Anonymous clone %s is allowed on %s", rsc->id, node->details->uname);
506 
507  } else if (rsc->running_on || g_hash_table_size(rsc->known_on)) {
508  /* If we've probed and/or started the resource anywhere, consider
509  * promotion scores only from nodes where we know the status. However,
510  * if the status of all nodes is unknown (e.g. cluster startup),
511  * skip this code, to make sure we take into account any permanent
512  * promotion scores set previously.
513  */
514  pe_node_t *known = pe_hash_table_lookup(rsc->known_on, node->details->id);
515 
516  match = pe_find_node_id(rsc->running_on, node->details->id);
517  if ((match == NULL) && (known == NULL)) {
518  pe_rsc_trace(rsc, "skipping %s (aka. %s) promotion score on %s because inactive",
519  rsc->id, rsc->clone_name, node->details->uname);
520  return score;
521  }
522  }
523 
524  match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
525  if (match == NULL) {
526  return score;
527 
528  } else if (match->weight < 0) {
529  pe_rsc_trace(rsc, "%s on %s has score: %d - ignoring",
530  rsc->id, match->details->uname, match->weight);
531  return score;
532  }
533 
534  if (rsc->clone_name) {
535  /* Use the name the lrm knows this resource as,
536  * since that's what crm_attribute --promotion would have used
537  */
538  name = rsc->clone_name;
539  }
540 
541  attr_value = lookup_promotion_score(rsc, node, name);
542  pe_rsc_trace(rsc, "promotion score for %s on %s = %s",
543  name, node->details->uname, crm_str(attr_value));
544 
545  if ((attr_value == NULL) && !pcmk_is_set(rsc->flags, pe_rsc_unique)) {
546  /* If we don't have any LRM history yet, we won't have clone_name -- in
547  * that case, for anonymous clones, try the resource name without any
548  * instance number.
549  */
550  name = clone_strip(rsc->id);
551  if (strcmp(rsc->id, name)) {
552  attr_value = lookup_promotion_score(rsc, node, name);
553  pe_rsc_trace(rsc, "stripped promotion score for %s on %s = %s",
554  name, node->details->uname, crm_str(attr_value));
555  }
556  free(name);
557  }
558 
559  if (attr_value != NULL) {
560  score = char2score(attr_value);
561  }
562 
563  return score;
564 }
565 
566 void
568 {
569  int score, new_score;
570  GList *gIter = rsc->children;
571  clone_variant_data_t *clone_data = NULL;
572 
573  get_clone_variant_data(clone_data, rsc);
574 
575  if (clone_data->added_promotion_scores) {
576  /* Make sure we only do this once */
577  return;
578  }
579 
580  clone_data->added_promotion_scores = true;
581 
582  for (; gIter != NULL; gIter = gIter->next) {
583  GHashTableIter iter;
584  pe_node_t *node = NULL;
585  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
586 
587  g_hash_table_iter_init(&iter, child_rsc->allowed_nodes);
588  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
589  if (can_run_resources(node) == FALSE) {
590  /* This node will never be promoted, so don't apply the
591  * promotion score, as that may lead to clone shuffling.
592  */
593  continue;
594  }
595 
596  score = promotion_score(child_rsc, node, 0);
597  if (score > 0) {
598  new_score = pe__add_scores(node->weight, score);
599  if (new_score != node->weight) {
600  pe_rsc_trace(rsc, "\t%s: Updating preference for %s (%d->%d)",
601  child_rsc->id, node->details->uname, node->weight, new_score);
602  node->weight = new_score;
603  }
604  }
605 
606  new_score = QB_MAX(child_rsc->priority, score);
607  if (new_score != child_rsc->priority) {
608  pe_rsc_trace(rsc, "\t%s: Updating priority (%d->%d)",
609  child_rsc->id, child_rsc->priority, new_score);
610  child_rsc->priority = new_score;
611  }
612  }
613  }
614 }
615 
616 static void
617 set_role_unpromoted(pe_resource_t *rsc, bool current)
618 {
619  GList *gIter = rsc->children;
620 
621  if (current) {
622  if (rsc->role == RSC_ROLE_STARTED) {
623  rsc->role = RSC_ROLE_UNPROMOTED;
624  }
625 
626  } else {
627  GList *allocated = NULL;
628 
629  rsc->fns->location(rsc, &allocated, FALSE);
631  "unpromoted instance");
632  g_list_free(allocated);
633  }
634 
635  for (; gIter != NULL; gIter = gIter->next) {
636  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
637 
638  set_role_unpromoted(child_rsc, current);
639  }
640 }
641 
642 static void
643 set_role_promoted(pe_resource_t *rsc)
644 {
645  GList *gIter = rsc->children;
646 
647  if (rsc->next_role == RSC_ROLE_UNKNOWN) {
648  pe__set_next_role(rsc, RSC_ROLE_PROMOTED, "promoted instance");
649  }
650 
651  for (; gIter != NULL; gIter = gIter->next) {
652  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
653 
654  set_role_promoted(child_rsc);
655  }
656 }
657 
658 pe_node_t *
660 {
661  int promoted = 0;
662  GList *gIter = NULL;
663  GList *gIter2 = NULL;
664  GHashTableIter iter;
665  pe_node_t *node = NULL;
666  pe_node_t *chosen = NULL;
667  enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
668  char score[33];
669  size_t len = sizeof(score);
670  clone_variant_data_t *clone_data = NULL;
671 
672  get_clone_variant_data(clone_data, rsc);
673 
674  // Repurpose count to track the number of promoted instances allocated
675  g_hash_table_iter_init(&iter, rsc->allowed_nodes);
676  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
677  node->count = 0;
678  }
679 
680  /*
681  * assign priority
682  */
683  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
684  GList *list = NULL;
685  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
686 
687  pe_rsc_trace(rsc, "Assigning priority for %s: %s", child_rsc->id,
688  role2text(child_rsc->next_role));
689 
690  if (child_rsc->fns->state(child_rsc, TRUE) == RSC_ROLE_STARTED) {
691  set_role_unpromoted(child_rsc, true);
692  }
693 
694  chosen = child_rsc->fns->location(child_rsc, &list, FALSE);
695  if (pcmk__list_of_multiple(list)) {
696  pcmk__config_err("Cannot promote non-colocated child %s",
697  child_rsc->id);
698  }
699 
700  g_list_free(list);
701  if (chosen == NULL) {
702  continue;
703  }
704 
705  next_role = child_rsc->fns->state(child_rsc, FALSE);
706  switch (next_role) {
707  case RSC_ROLE_STARTED:
708  case RSC_ROLE_UNKNOWN:
709  /*
710  * Default to -1 if no value is set
711  *
712  * This allows instances eligible for promotion to be specified
713  * based solely on rsc_location constraints,
714  * but prevents anyone from being promoted if
715  * neither a constraint nor a promotion score is present
716  */
717  child_rsc->priority = promotion_score(child_rsc, chosen, -1);
718  break;
719 
720  case RSC_ROLE_UNPROMOTED:
721  case RSC_ROLE_STOPPED:
722  child_rsc->priority = -INFINITY;
723  break;
724  case RSC_ROLE_PROMOTED:
725  /* We will arrive here if we're re-creating actions after a stonith
726  */
727  break;
728  default:
729  CRM_CHECK(FALSE /* unhandled */ ,
730  crm_err("Unknown resource role: %d for %s", next_role, child_rsc->id));
731  }
732 
733  apply_promoted_location(child_rsc, child_rsc->rsc_location, chosen);
734  apply_promoted_location(child_rsc, rsc->rsc_location, chosen);
735 
736  for (gIter2 = child_rsc->rsc_cons; gIter2 != NULL; gIter2 = gIter2->next) {
737  pcmk__colocation_t *cons = (pcmk__colocation_t *) gIter2->data;
738 
739  child_rsc->cmds->rsc_colocation_lh(child_rsc, cons->rsc_rh, cons,
740  data_set);
741  }
742 
743  child_rsc->sort_index = child_rsc->priority;
744  pe_rsc_trace(rsc, "Assigning priority for %s: %d", child_rsc->id, child_rsc->priority);
745 
746  if (next_role == RSC_ROLE_PROMOTED) {
747  child_rsc->sort_index = INFINITY;
748  }
749  }
750 
751  pe__show_node_weights(true, rsc, "Pre merge", rsc->allowed_nodes, data_set);
752  promotion_order(rsc, data_set);
753 
754  // Choose the first N eligible instances to be promoted
755  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
756  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
757  score2char_stack(child_rsc->sort_index, score, len);
758 
759  chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
761  if (data_set->priv != NULL) {
762  pcmk__output_t *out = data_set->priv;
763  out->message(out, "promotion-score", child_rsc, chosen, score);
764  }
765 
766  } else {
767  pe_rsc_trace(rsc, "%s promotion score on %s: %s", child_rsc->id,
768  (chosen? chosen->details->uname : "none"), score);
769  }
770 
771  chosen = NULL; /* nuke 'chosen' so that we don't promote more than the
772  * required number of instances
773  */
774 
775  if (child_rsc->sort_index < 0) {
776  pe_rsc_trace(rsc, "Not supposed to promote child: %s", child_rsc->id);
777 
778  } else if ((promoted < clone_data->promoted_max)
779  || !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
780  chosen = node_to_be_promoted_on(child_rsc);
781  }
782 
783  pe_rsc_debug(rsc, "%s promotion score: %d", child_rsc->id, child_rsc->priority);
784 
785  if (chosen == NULL) {
786  set_role_unpromoted(child_rsc, false);
787  continue;
788 
789  } else if ((child_rsc->role < RSC_ROLE_PROMOTED)
790  && !pcmk_is_set(data_set->flags, pe_flag_have_quorum)
791  && data_set->no_quorum_policy == no_quorum_freeze) {
792  crm_notice("Resource %s cannot be elevated from %s to %s: no-quorum-policy=freeze",
793  child_rsc->id, role2text(child_rsc->role), role2text(child_rsc->next_role));
794  set_role_unpromoted(child_rsc, false);
795  continue;
796  }
797 
798  chosen->count++;
799  pe_rsc_info(rsc, "Promoting %s (%s %s)",
800  child_rsc->id, role2text(child_rsc->role), chosen->details->uname);
801  set_role_promoted(child_rsc);
802  promoted++;
803  }
804 
805  pe_rsc_info(rsc, "%s: Promoted %d instances of a possible %d",
806  rsc->id, promoted, clone_data->promoted_max);
807 
808  return NULL;
809 }
810 
811 void
813 {
814  pe_action_t *action = NULL;
815  GList *gIter = rsc->children;
816  pe_action_t *action_complete = NULL;
817  gboolean any_promoting = FALSE;
818  gboolean any_demoting = FALSE;
819  pe_resource_t *last_promote_rsc = NULL;
820  pe_resource_t *last_demote_rsc = NULL;
821 
822  clone_variant_data_t *clone_data = NULL;
823 
824  get_clone_variant_data(clone_data, rsc);
825 
826  pe_rsc_debug(rsc, "Creating actions for %s", rsc->id);
827 
828  for (; gIter != NULL; gIter = gIter->next) {
829  gboolean child_promoting = FALSE;
830  gboolean child_demoting = FALSE;
831  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
832 
833  pe_rsc_trace(rsc, "Creating actions for %s", child_rsc->id);
834  child_rsc->cmds->create_actions(child_rsc, data_set);
835  check_promotable_actions(child_rsc, &child_demoting, &child_promoting);
836 
837  any_demoting = any_demoting || child_demoting;
838  any_promoting = any_promoting || child_promoting;
839  pe_rsc_trace(rsc, "Created actions for %s: %d %d", child_rsc->id, child_promoting,
840  child_demoting);
841  }
842 
843  /* promote */
844  action = create_pseudo_resource_op(rsc, RSC_PROMOTE, !any_promoting, TRUE, data_set);
845  action_complete = create_pseudo_resource_op(rsc, RSC_PROMOTED, !any_promoting, TRUE, data_set);
846  action_complete->priority = INFINITY;
847 
848  child_promoting_constraints(clone_data, pe_order_optional,
849  rsc, NULL, last_promote_rsc, data_set);
850 
851  if (clone_data->promote_notify == NULL) {
852  clone_data->promote_notify =
853  create_notification_boundaries(rsc, RSC_PROMOTE, action, action_complete, data_set);
854  }
855 
856  /* demote */
857  action = create_pseudo_resource_op(rsc, RSC_DEMOTE, !any_demoting, TRUE, data_set);
858  action_complete = create_pseudo_resource_op(rsc, RSC_DEMOTED, !any_demoting, TRUE, data_set);
859  action_complete->priority = INFINITY;
860 
861  child_demoting_constraints(clone_data, pe_order_optional, rsc, NULL, last_demote_rsc, data_set);
862 
863  if (clone_data->demote_notify == NULL) {
864  clone_data->demote_notify =
865  create_notification_boundaries(rsc, RSC_DEMOTE, action, action_complete, data_set);
866 
867  if (clone_data->promote_notify) {
868  /* If we ever wanted groups to have notifications we'd need to move this to native_internal_constraints() one day
869  * Requires exposing *_notify
870  */
871  order_actions(clone_data->stop_notify->post_done, clone_data->promote_notify->pre,
873  order_actions(clone_data->start_notify->post_done, clone_data->promote_notify->pre,
875  order_actions(clone_data->demote_notify->post_done, clone_data->promote_notify->pre,
877  order_actions(clone_data->demote_notify->post_done, clone_data->start_notify->pre,
879  order_actions(clone_data->demote_notify->post_done, clone_data->stop_notify->pre,
881  }
882  }
883 
884  /* restore the correct priority */
885 
886  gIter = rsc->children;
887  for (; gIter != NULL; gIter = gIter->next) {
888  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
889 
890  child_rsc->priority = rsc->priority;
891  }
892 }
893 
894 void
896 {
897  /* global stopped before start */
898  new_rsc_order(rsc, RSC_STOPPED, rsc, RSC_START, pe_order_optional, data_set);
899 
900  /* global stopped before promote */
902 
903  /* global demoted before start */
904  new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_START, pe_order_optional, data_set);
905 
906  /* global started before promote */
908 
909  /* global demoted before stop */
910  new_rsc_order(rsc, RSC_DEMOTED, rsc, RSC_STOP, pe_order_optional, data_set);
911 
912  /* global demote before demoted */
913  new_rsc_order(rsc, RSC_DEMOTE, rsc, RSC_DEMOTED, pe_order_optional, data_set);
914 
915  /* global demoted before promote */
917 }
918 
919 
920 void
922 {
923  GList *gIter = rsc->children;
924  pe_resource_t *last_rsc = NULL;
925  clone_variant_data_t *clone_data = NULL;
926 
927  get_clone_variant_data(clone_data, rsc);
928 
929  promote_demote_constraints(rsc, data_set);
930 
931  for (; gIter != NULL; gIter = gIter->next) {
932  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
933 
934  /* child demote before promote */
935  new_rsc_order(child_rsc, RSC_DEMOTE, child_rsc, RSC_PROMOTE, pe_order_optional, data_set);
936 
937  child_promoting_constraints(clone_data, pe_order_optional,
938  rsc, child_rsc, last_rsc, data_set);
939 
940  child_demoting_constraints(clone_data, pe_order_optional,
941  rsc, child_rsc, last_rsc, data_set);
942 
943  last_rsc = child_rsc;
944  }
945 }
946 
947 static void
948 node_hash_update_one(GHashTable * hash, pe_node_t * other, const char *attr, int score)
949 {
950  GHashTableIter iter;
951  pe_node_t *node = NULL;
952  const char *value = NULL;
953 
954  if (other == NULL) {
955  return;
956 
957  } else if (attr == NULL) {
958  attr = CRM_ATTR_UNAME;
959  }
960 
961  value = pe_node_attribute_raw(other, attr);
962  g_hash_table_iter_init(&iter, hash);
963  while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
964  const char *tmp = pe_node_attribute_raw(node, attr);
965 
966  if (pcmk__str_eq(value, tmp, pcmk__str_casei)) {
967  crm_trace("%s: %d + %d", node->details->uname, node->weight, other->weight);
968  node->weight = pe__add_scores(node->weight, score);
969  }
970  }
971 }
972 
973 void
975  pcmk__colocation_t *constraint,
976  pe_working_set_t *data_set)
977 {
978  GList *gIter = NULL;
979 
980  if (pcmk_is_set(rsc_lh->flags, pe_rsc_provisional)) {
981  GList *rhs = NULL;
982 
983  for (gIter = rsc_rh->children; gIter != NULL; gIter = gIter->next) {
984  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
985  pe_node_t *chosen = child_rsc->fns->location(child_rsc, NULL, FALSE);
986  enum rsc_role_e next_role = child_rsc->fns->state(child_rsc, FALSE);
987 
988  pe_rsc_trace(rsc_rh, "Processing: %s", child_rsc->id);
989  if (chosen != NULL && next_role == constraint->role_rh) {
990  pe_rsc_trace(rsc_rh, "Applying: %s %s %s %d", child_rsc->id,
991  role2text(next_role), chosen->details->uname, constraint->score);
992  if (constraint->score < INFINITY) {
993  node_hash_update_one(rsc_lh->allowed_nodes, chosen,
994  constraint->node_attribute, constraint->score);
995  }
996  rhs = g_list_prepend(rhs, chosen);
997  }
998  }
999 
1000  /* Only do this if it's not a promoted-with-promoted colocation. Doing
1001  * this unconditionally would prevent unpromoted instances from being
1002  * started.
1003  */
1004  if ((constraint->role_lh != RSC_ROLE_PROMOTED)
1005  || (constraint->role_rh != RSC_ROLE_PROMOTED)) {
1006 
1007  if (constraint->score >= INFINITY) {
1008  node_list_exclude(rsc_lh->allowed_nodes, rhs, TRUE);
1009  }
1010  }
1011  g_list_free(rhs);
1012 
1013  } else if (constraint->role_lh == RSC_ROLE_PROMOTED) {
1014  pe_resource_t *rh_child = find_compatible_child(rsc_lh, rsc_rh,
1015  constraint->role_rh,
1016  FALSE, data_set);
1017 
1018  if (rh_child == NULL && constraint->score >= INFINITY) {
1019  pe_rsc_trace(rsc_lh, "%s can't be promoted %s", rsc_lh->id, constraint->id);
1020  rsc_lh->priority = -INFINITY;
1021 
1022  } else if (rh_child != NULL) {
1023  int new_priority = pe__add_scores(rsc_lh->priority,
1024  constraint->score);
1025 
1026  pe_rsc_debug(rsc_lh, "Applying %s to %s", constraint->id, rsc_lh->id);
1027  pe_rsc_debug(rsc_lh, "\t%s: %d->%d", rsc_lh->id, rsc_lh->priority, new_priority);
1028  rsc_lh->priority = new_priority;
1029  }
1030  }
1031 
1032  return;
1033 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
enum rsc_role_e role_filter
Definition: internal.h:171
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:149
#define RSC_STOP
Definition: crm.h:204
#define crm_notice(fmt, args...)
Definition: logging.h:352
GHashTable * known_on
Definition: pe_types.h:366
const char * pe_node_attribute_calculated(const pe_node_t *node, const char *name, const pe_resource_t *rsc)
Definition: common.c:596
pe_resource_t * rsc_lh
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:19
GList * rsc_tickets
Definition: pe_types.h:359
#define INFINITY
Definition: crm.h:99
GList * rsc_cons
Definition: pe_types.h:356
gint sort_rsc_index(gconstpointer a, gconstpointer b)
Definition: utils.c:335
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:371
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition: pe_types.h:53
int priority
Definition: pe_types.h:407
pe_resource_t * container
Definition: pe_types.h:379
enum rsc_role_e role
Definition: pe_types.h:369
GList * children
Definition: pe_types.h:376
int count
Definition: pe_types.h:243
resource_alloc_functions_t * cmds
Definition: pe_types.h:332
gboolean standby
Definition: pe_types.h:459
enum rsc_role_e next_role
Definition: pe_types.h:370
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
int char2score(const char *score)
Definition: utils.c:61
#define pcmk__config_err(fmt...)
pe_resource_t * remote_rsc
Definition: pe_types.h:230
pe_resource_t * rsc_rh
#define pe_rsc_unique
Definition: pe_types.h:254
char * score2char_stack(int score, char *buf, size_t len)
Definition: utils.c:101
resource_object_functions_t * fns
Definition: pe_types.h:331
int(* message)(pcmk__output_t *out, const char *message_id,...)
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:161
GHashTable *(* merge_weights)(pe_resource_t *, const char *, GHashTable *, const char *, float, enum pe_weights)
char * pcmk_promotion_score_name(const char *rsc_id)
Return the name of the node attribute used as a promotion score.
Definition: attrd_client.c:320
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:202
void resource_location(pe_resource_t *rsc, pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition: utils.c:1588
GList * rsc_cons_lhs
Definition: pe_types.h:355
pe_ticket_t * ticket
enum crm_ais_msg_types type
Definition: cpg.c:48
#define RSC_START
Definition: crm.h:201
void pcmk__add_promotion_scores(pe_resource_t *rsc)
gboolean can_run_resources(const pe_node_t *node)
#define pe_flag_have_quorum
Definition: pe_types.h:94
const char * action
Definition: pcmk_fence.c:30
notify_data_t * create_notification_boundaries(pe_resource_t *rsc, const char *action, pe_action_t *start, pe_action_t *end, pe_working_set_t *data_set)
void promotable_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:47
#define pe_rsc_provisional
Definition: pe_types.h:258
const char * role2text(enum rsc_role_e role)
Definition: common.c:459
int weight
Definition: pe_types.h:241
#define pe_rsc_merging
Definition: pe_types.h:260
void(* create_actions)(pe_resource_t *, pe_working_set_t *)
void create_promotable_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
int rc
Definition: pcmk_fence.c:35
pe_action_t * create_pseudo_resource_op(pe_resource_t *rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:903
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
char * clone_strip(const char *last_rsc_id)
Definition: unpack.c:1634
pe_resource_t *(* find_rsc)(pe_resource_t *parent, const char *search, const pe_node_t *node, int flags)
Definition: pe_types.h:45
match only clone instances
Definition: pe_types.h:86
char * task
Definition: pe_types.h:413
#define CRM_ATTR_UNAME
Definition: crm.h:114
#define crm_trace(fmt, args...)
Definition: logging.h:356
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
void promote_demote_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
struct pe_node_shared_s * details
Definition: pe_types.h:244
bool pcmk__is_daemon
Definition: logging.c:47
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1802
unsigned long long flags
Definition: pe_types.h:347
const char * uname
Definition: pe_types.h:209
char * clone_name
Definition: pe_types.h:321
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition: common.c:635
GList * actions
Definition: pe_types.h:358
gboolean granted
Definition: pe_types.h:457
int new_rsc_order(pe_resource_t *lh_rsc, const char *lh_task, pe_resource_t *rh_rsc, const char *rh_task, enum pe_ordering type, pe_working_set_t *data_set)
#define RSC_DEMOTED
Definition: crm.h:210
const char * id
Definition: pe_types.h:208
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition: status.c:418
pe_resource_t * find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current, pe_working_set_t *data_set)
#define RSC_STARTED
Definition: crm.h:202
int sort_index
Definition: pe_types.h:341
int pe__add_scores(int score1, int score2)
Definition: common.c:516
#define crm_err(fmt, args...)
Definition: logging.h:350
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_PROMOTE
Definition: crm.h:207
void pe__set_next_role(pe_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition: complex.c:1116
pe_weights
This structure contains everything that makes up a single output formatter.
GList * rsc_location
Definition: pe_types.h:357
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:53
#define crm_str(x)
Definition: logging.h:376
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
GList * running_on
Definition: pe_types.h:365
enum pe_action_flags flags
Definition: pe_types.h:418
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:54
#define order_start_start(rsc1, rsc2, type)
const char * node_attribute
#define RSC_STOPPED
Definition: crm.h:205
#define RSC_PROMOTED
Definition: crm.h:208
void promotable_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:20
unsigned long long flags
Definition: pe_types.h:146
char * name
Definition: pcmk_fence.c:31
pe_node_t * pcmk__set_instance_roles(pe_resource_t *rsc, pe_working_set_t *data_set)
#define pe_flag_show_scores
Definition: pe_types.h:133
#define crm_info(fmt, args...)
Definition: logging.h:353
#define pe_rsc_managed
Definition: pe_types.h:249
void(* rsc_colocation_lh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
pe_ordering
Definition: pe_types.h:482
uint64_t flags
Definition: remote.c:149
match resource active on specified node
Definition: pe_types.h:87
#define RSC_DEMOTE
Definition: crm.h:209
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:18
char * id
Definition: pe_types.h:320
GHashTable * allowed_nodes
Definition: pe_types.h:367