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