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