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