pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmk_sched_bundle.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2021 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <stdbool.h>
13 
14 #include <crm/msg_xml.h>
15 #include <pacemaker-internal.h>
16 
17 #define PE__VARIANT_BUNDLE 1
18 #include <lib/pengine/variant.h>
19 
20 static bool
21 is_bundle_node(pe__bundle_variant_data_t *data, pe_node_t *node)
22 {
23  for (GList *gIter = data->replicas; gIter != NULL; gIter = gIter->next) {
24  pe__bundle_replica_t *replica = gIter->data;
25 
26  if (node->details == replica->node->details) {
27  return TRUE;
28  }
29  }
30  return FALSE;
31 }
32 
33 gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set);
34 void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
35  int max, int per_host_max, pe_working_set_t * data_set);
36 
37 static GList *
38 get_container_list(pe_resource_t *rsc)
39 {
40  GList *containers = NULL;
41 
42  if (rsc->variant == pe_container) {
43  pe__bundle_variant_data_t *data = NULL;
44 
45  get_bundle_variant_data(data, rsc);
46  for (GList *gIter = data->replicas; gIter != NULL;
47  gIter = gIter->next) {
48  pe__bundle_replica_t *replica = gIter->data;
49 
50  containers = g_list_append(containers, replica->container);
51  }
52  }
53  return containers;
54 }
55 
56 static inline GList *
57 get_containers_or_children(pe_resource_t *rsc)
58 {
59  return (rsc->variant == pe_container)?
60  get_container_list(rsc) : rsc->children;
61 }
62 
63 static bool
64 migration_threshold_reached(pe_resource_t *rsc, pe_node_t *node,
65  pe_working_set_t *data_set)
66 {
67  int fail_count, countdown;
68 
69  /* Migration threshold of 0 means never force away */
70  if (rsc->migration_threshold == 0) {
71  return FALSE;
72  }
73 
74  // If we're ignoring failures, also ignore the migration threshold
76  return FALSE;
77  }
78 
79  /* If there are no failures, there's no need to force away */
80  fail_count = pe_get_failcount(node, rsc, NULL,
82  data_set);
83  if (fail_count <= 0) {
84  return FALSE;
85  }
86 
87  /* How many more times recovery will be tried on this node */
88  countdown = QB_MAX(rsc->migration_threshold - fail_count, 0);
89 
90  if (countdown == 0) {
91  crm_warn("Forcing %s away from %s after %d failures (max=%d)",
92  rsc->id, node->details->uname, fail_count,
93  rsc->migration_threshold);
94  return TRUE;
95  }
96 
97  crm_info("%s can fail %d more times on %s before being forced off",
98  rsc->id, countdown, node->details->uname);
99  return FALSE;
100 }
101 
102 pe_node_t *
104  pe_working_set_t *data_set)
105 {
106  GList *containers = NULL;
107  GList *nodes = NULL;
108  pe__bundle_variant_data_t *bundle_data = NULL;
109 
110  CRM_CHECK(rsc != NULL, return NULL);
111 
112  get_bundle_variant_data(bundle_data, rsc);
113 
115  containers = get_container_list(rsc);
116 
118  rsc, __func__, rsc->allowed_nodes, data_set);
119 
120  nodes = g_hash_table_get_values(rsc->allowed_nodes);
121  nodes = sort_nodes_by_weight(nodes, NULL, data_set);
122  containers = g_list_sort_with_data(containers, sort_clone_instance, data_set);
123  distribute_children(rsc, containers, nodes, bundle_data->nreplicas,
124  bundle_data->nreplicas_per_host, data_set);
125  g_list_free(nodes);
126  g_list_free(containers);
127 
128  for (GList *gIter = bundle_data->replicas; gIter != NULL;
129  gIter = gIter->next) {
130  pe__bundle_replica_t *replica = gIter->data;
131  pe_node_t *container_host = NULL;
132 
133  CRM_ASSERT(replica);
134  if (replica->ip) {
135  pe_rsc_trace(rsc, "Allocating bundle %s IP %s",
136  rsc->id, replica->ip->id);
137  replica->ip->cmds->allocate(replica->ip, prefer, data_set);
138  }
139 
140  container_host = replica->container->allocated_to;
141  if (replica->remote && pe__is_guest_or_remote_node(container_host)) {
142  /* We need 'nested' connection resources to be on the same
143  * host because pacemaker-remoted only supports a single
144  * active connection
145  */
146  pcmk__new_colocation("child-remote-with-docker-remote", NULL,
147  INFINITY, replica->remote,
148  container_host->details->remote_rsc, NULL,
149  NULL, true, data_set);
150  }
151 
152  if (replica->remote) {
153  pe_rsc_trace(rsc, "Allocating bundle %s connection %s",
154  rsc->id, replica->remote->id);
155  replica->remote->cmds->allocate(replica->remote, prefer,
156  data_set);
157  }
158 
159  // Explicitly allocate replicas' children before bundle child
160  if (replica->child) {
161  pe_node_t *node = NULL;
162  GHashTableIter iter;
163 
164  g_hash_table_iter_init(&iter, replica->child->allowed_nodes);
165  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
166  if (node->details != replica->node->details) {
167  node->weight = -INFINITY;
168  } else if (!migration_threshold_reached(replica->child, node,
169  data_set)) {
170  node->weight = INFINITY;
171  }
172  }
173 
174  pe__set_resource_flags(replica->child->parent, pe_rsc_allocating);
175  pe_rsc_trace(rsc, "Allocating bundle %s replica child %s",
176  rsc->id, replica->child->id);
177  replica->child->cmds->allocate(replica->child, replica->node,
178  data_set);
179  pe__clear_resource_flags(replica->child->parent,
181  }
182  }
183 
184  if (bundle_data->child) {
185  pe_node_t *node = NULL;
186  GHashTableIter iter;
187  g_hash_table_iter_init(&iter, bundle_data->child->allowed_nodes);
188  while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
189  if (is_bundle_node(bundle_data, node)) {
190  node->weight = 0;
191  } else {
192  node->weight = -INFINITY;
193  }
194  }
195  pe_rsc_trace(rsc, "Allocating bundle %s child %s",
196  rsc->id, bundle_data->child->id);
197  bundle_data->child->cmds->allocate(bundle_data->child, prefer, data_set);
198  }
199 
201  return NULL;
202 }
203 
204 
205 void
207 {
208  pe_action_t *action = NULL;
209  GList *containers = NULL;
210  pe__bundle_variant_data_t *bundle_data = NULL;
211 
212  CRM_CHECK(rsc != NULL, return);
213 
214  containers = get_container_list(rsc);
215  get_bundle_variant_data(bundle_data, rsc);
216  for (GList *gIter = bundle_data->replicas; gIter != NULL;
217  gIter = gIter->next) {
218  pe__bundle_replica_t *replica = gIter->data;
219 
220  CRM_ASSERT(replica);
221  if (replica->ip) {
222  replica->ip->cmds->create_actions(replica->ip, data_set);
223  }
224  if (replica->container) {
225  replica->container->cmds->create_actions(replica->container,
226  data_set);
227  }
228  if (replica->remote) {
229  replica->remote->cmds->create_actions(replica->remote, data_set);
230  }
231  }
232 
233  clone_create_pseudo_actions(rsc, containers, NULL, NULL, data_set);
234 
235  if (bundle_data->child) {
236  bundle_data->child->cmds->create_actions(bundle_data->child, data_set);
237 
238  if (pcmk_is_set(bundle_data->child->flags, pe_rsc_promotable)) {
239  /* promote */
240  create_pseudo_resource_op(rsc, RSC_PROMOTE, TRUE, TRUE, data_set);
241  action = create_pseudo_resource_op(rsc, RSC_PROMOTED, TRUE, TRUE, data_set);
242  action->priority = INFINITY;
243 
244  /* demote */
245  create_pseudo_resource_op(rsc, RSC_DEMOTE, TRUE, TRUE, data_set);
246  action = create_pseudo_resource_op(rsc, RSC_DEMOTED, TRUE, TRUE, data_set);
247  action->priority = INFINITY;
248  }
249  }
250 
251  g_list_free(containers);
252 }
253 
254 void
256  pe_working_set_t *data_set)
257 {
258  pe__bundle_variant_data_t *bundle_data = NULL;
259 
260  CRM_CHECK(rsc != NULL, return);
261 
262  get_bundle_variant_data(bundle_data, rsc);
263 
264  if (bundle_data->child) {
265  new_rsc_order(rsc, RSC_START, bundle_data->child, RSC_START,
267  new_rsc_order(rsc, RSC_STOP, bundle_data->child, RSC_STOP,
269 
270  if (bundle_data->child->children) {
271  new_rsc_order(bundle_data->child, RSC_STARTED, rsc, RSC_STARTED,
273  new_rsc_order(bundle_data->child, RSC_STOPPED, rsc, RSC_STOPPED,
275  } else {
276  new_rsc_order(bundle_data->child, RSC_START, rsc, RSC_STARTED,
278  new_rsc_order(bundle_data->child, RSC_STOP, rsc, RSC_STOPPED,
280  }
281  }
282 
283  for (GList *gIter = bundle_data->replicas; gIter != NULL;
284  gIter = gIter->next) {
285  pe__bundle_replica_t *replica = gIter->data;
286 
287  CRM_ASSERT(replica);
288  CRM_ASSERT(replica->container);
289 
290  replica->container->cmds->internal_constraints(replica->container,
291  data_set);
292 
293  order_start_start(rsc, replica->container,
295 
296  if (replica->child) {
297  order_stop_stop(rsc, replica->child,
299  }
300  order_stop_stop(rsc, replica->container,
302  new_rsc_order(replica->container, RSC_START, rsc, RSC_STARTED,
304  new_rsc_order(replica->container, RSC_STOP, rsc, RSC_STOPPED,
306 
307  if (replica->ip) {
308  replica->ip->cmds->internal_constraints(replica->ip, data_set);
309 
310  // Start ip then container
311  new_rsc_order(replica->ip, RSC_START, replica->container, RSC_START,
313  new_rsc_order(replica->container, RSC_STOP, replica->ip, RSC_STOP,
315 
316  pcmk__new_colocation("ip-with-docker", NULL, INFINITY, replica->ip,
317  replica->container, NULL, NULL, true,
318  data_set);
319  }
320 
321  if (replica->remote) {
322  /* This handles ordering and colocating remote relative to container
323  * (via "resource-with-container"). Since IP is also ordered and
324  * colocated relative to the container, we don't need to do anything
325  * explicit here with IP.
326  */
327  replica->remote->cmds->internal_constraints(replica->remote,
328  data_set);
329  }
330 
331  if (replica->child) {
332  CRM_ASSERT(replica->remote);
333 
334  // "Start remote then child" is implicit in scheduler's remote logic
335  }
336 
337  }
338 
339  if (bundle_data->child) {
340  bundle_data->child->cmds->internal_constraints(bundle_data->child, data_set);
341  if (pcmk_is_set(bundle_data->child->flags, pe_rsc_promotable)) {
342  promote_demote_constraints(rsc, data_set);
343 
344  /* child demoted before global demoted */
345  new_rsc_order(bundle_data->child, RSC_DEMOTED, rsc, RSC_DEMOTED,
347 
348  /* global demote before child demote */
349  new_rsc_order(rsc, RSC_DEMOTE, bundle_data->child, RSC_DEMOTE,
351 
352  /* child promoted before global promoted */
353  new_rsc_order(bundle_data->child, RSC_PROMOTED, rsc, RSC_PROMOTED,
355 
356  /* global promote before child promote */
357  new_rsc_order(rsc, RSC_PROMOTE, bundle_data->child, RSC_PROMOTE,
359  }
360 
361  } else {
362 // int type = pe_order_optional | pe_order_implies_then | pe_order_restart;
363 // custom_action_order(rsc, pcmk__op_key(rsc->id, RSC_STOP, 0), NULL,
364 // rsc, pcmk__op_key(rsc->id, RSC_START, 0), NULL, pe_order_optional, data_set);
365  }
366 }
367 
368 static pe_resource_t *
369 compatible_replica_for_node(pe_resource_t *rsc_lh, pe_node_t *candidate,
370  pe_resource_t *rsc, enum rsc_role_e filter,
371  gboolean current)
372 {
373  pe__bundle_variant_data_t *bundle_data = NULL;
374 
375  CRM_CHECK(candidate != NULL, return NULL);
376  get_bundle_variant_data(bundle_data, rsc);
377 
378  crm_trace("Looking for compatible child from %s for %s on %s",
379  rsc_lh->id, rsc->id, candidate->details->uname);
380 
381  for (GList *gIter = bundle_data->replicas; gIter != NULL;
382  gIter = gIter->next) {
383  pe__bundle_replica_t *replica = gIter->data;
384 
385  if (is_child_compatible(replica->container, candidate, filter, current)) {
386  crm_trace("Pairing %s with %s on %s",
387  rsc_lh->id, replica->container->id,
388  candidate->details->uname);
389  return replica->container;
390  }
391  }
392 
393  crm_trace("Can't pair %s with %s", rsc_lh->id, rsc->id);
394  return NULL;
395 }
396 
397 static pe_resource_t *
398 compatible_replica(pe_resource_t *rsc_lh, pe_resource_t *rsc,
399  enum rsc_role_e filter, gboolean current,
400  pe_working_set_t *data_set)
401 {
402  GList *scratch = NULL;
403  pe_resource_t *pair = NULL;
404  pe_node_t *active_node_lh = NULL;
405 
406  active_node_lh = rsc_lh->fns->location(rsc_lh, NULL, current);
407  if (active_node_lh) {
408  return compatible_replica_for_node(rsc_lh, active_node_lh, rsc, filter,
409  current);
410  }
411 
412  scratch = g_hash_table_get_values(rsc_lh->allowed_nodes);
413  scratch = sort_nodes_by_weight(scratch, NULL, data_set);
414 
415  for (GList *gIter = scratch; gIter != NULL; gIter = gIter->next) {
416  pe_node_t *node = (pe_node_t *) gIter->data;
417 
418  pair = compatible_replica_for_node(rsc_lh, node, rsc, filter, current);
419  if (pair) {
420  goto done;
421  }
422  }
423 
424  pe_rsc_debug(rsc, "Can't pair %s with %s", rsc_lh->id, (rsc? rsc->id : "none"));
425  done:
426  g_list_free(scratch);
427  return pair;
428 }
429 
430 void
432  pcmk__colocation_t *constraint,
433  pe_working_set_t *data_set)
434 {
435  /* -- Never called --
436  *
437  * Instead we add the colocation constraints to the child and call from there
438  */
439  CRM_ASSERT(FALSE);
440 }
441 
443 {
444  /* Strictly speaking, there should be a 'copies_per_node' addition
445  * to the resource function table and each case would be a
446  * function. However that would be serious overkill to return an
447  * int. In fact, it seems to me that both function tables
448  * could/should be replaced by resources.{c,h} full of
449  * rsc_{some_operation} functions containing a switch as below
450  * which calls out to functions named {variant}_{some_operation}
451  * as needed.
452  */
453  switch(rsc->variant) {
454  case pe_unknown:
455  return 0;
456  case pe_native:
457  case pe_group:
458  return 1;
459  case pe_clone:
460  {
461  const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
462 
463  if (max_clones_node == NULL) {
464  return 1;
465 
466  } else {
467  int max_i;
468 
469  pcmk__scan_min_int(max_clones_node, &max_i, 0);
470  return max_i;
471  }
472  }
473  case pe_container:
474  {
475  pe__bundle_variant_data_t *data = NULL;
476  get_bundle_variant_data(data, rsc);
477  return data->nreplicas_per_host;
478  }
479  }
480  return 0;
481 }
482 
483 void
485  pcmk__colocation_t *constraint,
486  pe_working_set_t *data_set)
487 {
488  GList *allocated_rhs = NULL;
489  pe__bundle_variant_data_t *bundle_data = NULL;
490 
491  CRM_CHECK(constraint != NULL, return);
492  CRM_CHECK(rsc_lh != NULL, pe_err("rsc_lh was NULL for %s", constraint->id); return);
493  CRM_CHECK(rsc != NULL, pe_err("rsc was NULL for %s", constraint->id); return);
494  CRM_ASSERT(rsc_lh->variant == pe_native);
495 
496  if (pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
497  pe_rsc_trace(rsc, "%s is still provisional", rsc->id);
498  return;
499 
500  } else if(constraint->rsc_lh->variant > pe_group) {
501  pe_resource_t *rh_child = compatible_replica(rsc_lh, rsc,
502  RSC_ROLE_UNKNOWN, FALSE,
503  data_set);
504 
505  if (rh_child) {
506  pe_rsc_debug(rsc, "Pairing %s with %s", rsc_lh->id, rh_child->id);
507  rsc_lh->cmds->rsc_colocation_lh(rsc_lh, rh_child, constraint,
508  data_set);
509 
510  } else if (constraint->score >= INFINITY) {
511  crm_notice("Cannot pair %s with instance of %s", rsc_lh->id, rsc->id);
512  assign_node(rsc_lh, NULL, TRUE);
513 
514  } else {
515  pe_rsc_debug(rsc, "Cannot pair %s with instance of %s", rsc_lh->id, rsc->id);
516  }
517 
518  return;
519  }
520 
521  get_bundle_variant_data(bundle_data, rsc);
522  pe_rsc_trace(rsc, "Processing constraint %s: %s -> %s %d",
523  constraint->id, rsc_lh->id, rsc->id, constraint->score);
524 
525  for (GList *gIter = bundle_data->replicas; gIter != NULL;
526  gIter = gIter->next) {
527  pe__bundle_replica_t *replica = gIter->data;
528 
529  if (constraint->score < INFINITY) {
530  replica->container->cmds->rsc_colocation_rh(rsc_lh,
531  replica->container,
532  constraint, data_set);
533 
534  } else {
535  pe_node_t *chosen = replica->container->fns->location(replica->container,
536  NULL, FALSE);
537 
538  if ((chosen == NULL)
539  || is_set_recursive(replica->container, pe_rsc_block, TRUE)) {
540  continue;
541  }
542  if ((constraint->role_rh >= RSC_ROLE_PROMOTED)
543  && (replica->child == NULL)) {
544  continue;
545  }
546  if ((constraint->role_rh >= RSC_ROLE_PROMOTED)
547  && (replica->child->next_role < RSC_ROLE_PROMOTED)) {
548  continue;
549  }
550 
551  pe_rsc_trace(rsc, "Allowing %s: %s %d", constraint->id, chosen->details->uname, chosen->weight);
552  allocated_rhs = g_list_prepend(allocated_rhs, chosen);
553  }
554  }
555 
556  if (constraint->score >= INFINITY) {
557  node_list_exclude(rsc_lh->allowed_nodes, allocated_rhs, FALSE);
558  }
559  g_list_free(allocated_rhs);
560 }
561 
562 enum pe_action_flags
564 {
565  GList *containers = NULL;
566  enum pe_action_flags flags = 0;
567  pe__bundle_variant_data_t *data = NULL;
568 
569  get_bundle_variant_data(data, action->rsc);
570  if(data->child) {
571  enum action_tasks task = get_complex_task(data->child, action->task, TRUE);
572  switch(task) {
573  case no_action:
574  case action_notify:
575  case action_notified:
576  case action_promote:
577  case action_promoted:
578  case action_demote:
579  case action_demoted:
580  return summary_action_flags(action, data->child->children, node);
581  default:
582  break;
583  }
584  }
585 
586  containers = get_container_list(action->rsc);
587  flags = summary_action_flags(action, containers, node);
588  g_list_free(containers);
589  return flags;
590 }
591 
594  enum rsc_role_e filter, gboolean current)
595 {
596  GList *gIter = NULL;
597  GList *children = NULL;
598 
599  if (local_node == NULL) {
600  crm_err("Can't colocate unrunnable child %s with %s", local_child->id, rsc->id);
601  return NULL;
602  }
603 
604  crm_trace("Looking for compatible child from %s for %s on %s",
605  local_child->id, rsc->id, local_node->details->uname);
606 
607  children = get_containers_or_children(rsc);
608  for (gIter = children; gIter != NULL; gIter = gIter->next) {
609  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
610 
611  if(is_child_compatible(child_rsc, local_node, filter, current)) {
612  crm_trace("Pairing %s with %s on %s",
613  local_child->id, child_rsc->id, local_node->details->uname);
614  return child_rsc;
615  }
616  }
617 
618  crm_trace("Can't pair %s with %s", local_child->id, rsc->id);
619  if(children != rsc->children) {
620  g_list_free(children);
621  }
622  return NULL;
623 }
624 
625 static pe__bundle_replica_t *
626 replica_for_container(pe_resource_t *rsc, pe_resource_t *container,
627  pe_node_t *node)
628 {
629  if (rsc->variant == pe_container) {
630  pe__bundle_variant_data_t *data = NULL;
631 
632  get_bundle_variant_data(data, rsc);
633  for (GList *gIter = data->replicas; gIter != NULL;
634  gIter = gIter->next) {
635  pe__bundle_replica_t *replica = gIter->data;
636 
637  if (replica->child
638  && (container == replica->container)
639  && (node->details == replica->node->details)) {
640  return replica;
641  }
642  }
643  }
644  return NULL;
645 }
646 
647 static enum pe_graph_flags
648 multi_update_interleave_actions(pe_action_t *first, pe_action_t *then,
649  pe_node_t *node, enum pe_action_flags flags,
650  enum pe_action_flags filter,
651  enum pe_ordering type,
652  pe_working_set_t *data_set)
653 {
654  GList *gIter = NULL;
655  GList *children = NULL;
656  gboolean current = FALSE;
657  enum pe_graph_flags changed = pe_graph_none;
658 
659  /* Fix this - lazy */
660  if (pcmk__ends_with(first->uuid, "_stopped_0")
661  || pcmk__ends_with(first->uuid, "_demoted_0")) {
662  current = TRUE;
663  }
664 
665  children = get_containers_or_children(then->rsc);
666  for (gIter = children; gIter != NULL; gIter = gIter->next) {
667  pe_resource_t *then_child = gIter->data;
668  pe_resource_t *first_child = find_compatible_child(then_child,
669  first->rsc,
671  current, data_set);
672  if (first_child == NULL && current) {
673  crm_trace("Ignore");
674 
675  } else if (first_child == NULL) {
676  crm_debug("No match found for %s (%d / %s / %s)", then_child->id, current, first->uuid, then->uuid);
677 
678  /* Me no like this hack - but what else can we do?
679  *
680  * If there is no-one active or about to be active
681  * on the same node as then_child, then they must
682  * not be allowed to start
683  */
684  if (type & (pe_order_runnable_left | pe_order_implies_then) /* Mandatory */ ) {
685  pe_rsc_info(then->rsc, "Inhibiting %s from being active", then_child->id);
686  if(assign_node(then_child, NULL, TRUE)) {
688  }
689  }
690 
691  } else {
692  pe_action_t *first_action = NULL;
693  pe_action_t *then_action = NULL;
694 
695  enum action_tasks task = clone_child_action(first);
696  const char *first_task = task2text(task);
697 
698  pe__bundle_replica_t *first_replica = NULL;
699  pe__bundle_replica_t *then_replica = NULL;
700 
701  first_replica = replica_for_container(first->rsc, first_child,
702  node);
703  if (strstr(first->task, "stop") && first_replica && first_replica->child) {
704  /* Except for 'stopped' we should be looking at the
705  * in-container resource, actions for the child will
706  * happen later and are therefor more likely to align
707  * with the user's intent.
708  */
709  first_action = find_first_action(first_replica->child->actions,
710  NULL, task2text(task), node);
711  } else {
712  first_action = find_first_action(first_child->actions, NULL, task2text(task), node);
713  }
714 
715  then_replica = replica_for_container(then->rsc, then_child, node);
716  if (strstr(then->task, "mote")
717  && then_replica && then_replica->child) {
718  /* Promote/demote actions will never be found for the
719  * container resource, look in the child instead
720  *
721  * Alternatively treat:
722  * 'XXXX then promote YYYY' as 'XXXX then start container for YYYY', and
723  * 'demote XXXX then stop YYYY' as 'stop container for XXXX then stop YYYY'
724  */
725  then_action = find_first_action(then_replica->child->actions,
726  NULL, then->task, node);
727  } else {
728  then_action = find_first_action(then_child->actions, NULL, then->task, node);
729  }
730 
731  if (first_action == NULL) {
732  if (!pcmk_is_set(first_child->flags, pe_rsc_orphan)
733  && !pcmk__str_any_of(first_task, RSC_STOP, RSC_DEMOTE, NULL)) {
734  crm_err("Internal error: No action found for %s in %s (first)",
735  first_task, first_child->id);
736 
737  } else {
738  crm_trace("No action found for %s in %s%s (first)",
739  first_task, first_child->id,
740  pcmk_is_set(first_child->flags, pe_rsc_orphan)? " (ORPHAN)" : "");
741  }
742  continue;
743  }
744 
745  /* We're only interested if 'then' is neither stopping nor being demoted */
746  if (then_action == NULL) {
747  if (!pcmk_is_set(then_child->flags, pe_rsc_orphan)
748  && !pcmk__str_any_of(then->task, RSC_STOP, RSC_DEMOTE, NULL)) {
749  crm_err("Internal error: No action found for %s in %s (then)",
750  then->task, then_child->id);
751 
752  } else {
753  crm_trace("No action found for %s in %s%s (then)",
754  then->task, then_child->id,
755  pcmk_is_set(then_child->flags, pe_rsc_orphan)? " (ORPHAN)" : "");
756  }
757  continue;
758  }
759 
760  if (order_actions(first_action, then_action, type)) {
761  crm_debug("Created constraint for %s (%d) -> %s (%d) %.6x",
762  first_action->uuid,
763  pcmk_is_set(first_action->flags, pe_action_optional),
764  then_action->uuid,
765  pcmk_is_set(then_action->flags, pe_action_optional),
766  type);
767  pe__set_graph_flags(changed, first,
769  }
770  if(first_action && then_action) {
771  changed |= then_child->cmds->update_actions(first_action,
772  then_action, node,
773  first_child->cmds->action_flags(first_action, node),
774  filter, type, data_set);
775  } else {
776  crm_err("Nothing found either for %s (%p) or %s (%p) %s",
777  first_child->id, first_action,
778  then_child->id, then_action, task2text(task));
779  }
780  }
781  }
782 
783  if(children != then->rsc->children) {
784  g_list_free(children);
785  }
786  return changed;
787 }
788 
789 static bool
790 can_interleave_actions(pe_action_t *first, pe_action_t *then)
791 {
792  bool interleave = FALSE;
793  pe_resource_t *rsc = NULL;
794  const char *interleave_s = NULL;
795 
796  if(first->rsc == NULL || then->rsc == NULL) {
797  crm_trace("Not interleaving %s with %s (both must be resources)", first->uuid, then->uuid);
798  return FALSE;
799  } else if(first->rsc == then->rsc) {
800  crm_trace("Not interleaving %s with %s (must belong to different resources)", first->uuid, then->uuid);
801  return FALSE;
802  } else if(first->rsc->variant < pe_clone || then->rsc->variant < pe_clone) {
803  crm_trace("Not interleaving %s with %s (both sides must be clones or bundles)", first->uuid, then->uuid);
804  return FALSE;
805  }
806 
807  if (pcmk__ends_with(then->uuid, "_stop_0")
808  || pcmk__ends_with(then->uuid, "_demote_0")) {
809  rsc = first->rsc;
810  } else {
811  rsc = then->rsc;
812  }
813 
814  interleave_s = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERLEAVE);
815  interleave = crm_is_true(interleave_s);
816  crm_trace("Interleave %s -> %s: %s (based on %s)",
817  first->uuid, then->uuid, interleave ? "yes" : "no", rsc->id);
818 
819  return interleave;
820 }
821 
822 enum pe_graph_flags
824  pe_node_t *node, enum pe_action_flags flags,
825  enum pe_action_flags filter, enum pe_ordering type,
826  pe_working_set_t *data_set)
827 {
828  enum pe_graph_flags changed = pe_graph_none;
829 
830  crm_trace("%s -> %s", first->uuid, then->uuid);
831 
832  if(can_interleave_actions(first, then)) {
833  changed = multi_update_interleave_actions(first, then, node, flags,
834  filter, type, data_set);
835 
836  } else if(then->rsc) {
837  GList *gIter = NULL;
838  GList *children = NULL;
839 
840  // Handle the 'primitive' ordering case
841  changed |= native_update_actions(first, then, node, flags, filter,
842  type, data_set);
843 
844  // Now any children (or containers in the case of a bundle)
845  children = get_containers_or_children(then->rsc);
846  for (gIter = children; gIter != NULL; gIter = gIter->next) {
847  pe_resource_t *then_child = (pe_resource_t *) gIter->data;
848  enum pe_graph_flags then_child_changed = pe_graph_none;
849  pe_action_t *then_child_action = find_first_action(then_child->actions, NULL, then->task, node);
850 
851  if (then_child_action) {
852  enum pe_action_flags then_child_flags = then_child->cmds->action_flags(then_child_action, node);
853 
854  if (pcmk_is_set(then_child_flags, pe_action_runnable)) {
855  then_child_changed |= then_child->cmds->update_actions(first,
856  then_child_action, node, flags, filter, type, data_set);
857  }
858  changed |= then_child_changed;
859  if (then_child_changed & pe_graph_updated_then) {
860  for (GList *lpc = then_child_action->actions_after; lpc != NULL; lpc = lpc->next) {
861  pe_action_wrapper_t *next = (pe_action_wrapper_t *) lpc->data;
862  update_action(next->action, data_set);
863  }
864  }
865  }
866  }
867 
868  if(children != then->rsc->children) {
869  g_list_free(children);
870  }
871  }
872  return changed;
873 }
874 
875 void
877 {
878  pe__bundle_variant_data_t *bundle_data = NULL;
879  get_bundle_variant_data(bundle_data, rsc);
880 
881  native_rsc_location(rsc, constraint);
882 
883  for (GList *gIter = bundle_data->replicas; gIter != NULL;
884  gIter = gIter->next) {
885  pe__bundle_replica_t *replica = gIter->data;
886 
887  if (replica->container) {
888  replica->container->cmds->rsc_location(replica->container,
889  constraint);
890  }
891  if (replica->ip) {
892  replica->ip->cmds->rsc_location(replica->ip, constraint);
893  }
894  }
895 
896  if (bundle_data->child
897  && ((constraint->role_filter == RSC_ROLE_UNPROMOTED)
898  || (constraint->role_filter == RSC_ROLE_PROMOTED))) {
899  bundle_data->child->cmds->rsc_location(bundle_data->child, constraint);
900  bundle_data->child->rsc_location = g_list_prepend(bundle_data->child->rsc_location,
901  constraint);
902  }
903 }
904 
905 void
907 {
908  pe__bundle_variant_data_t *bundle_data = NULL;
909 
910  CRM_CHECK(rsc != NULL, return);
911 
912  get_bundle_variant_data(bundle_data, rsc);
913 
914  if (bundle_data->child) {
915  bundle_data->child->cmds->expand(bundle_data->child, data_set);
916  }
917 
918  for (GList *gIter = bundle_data->replicas; gIter != NULL;
919  gIter = gIter->next) {
920  pe__bundle_replica_t *replica = gIter->data;
921 
922  CRM_ASSERT(replica);
923  if (replica->remote && replica->container
924  && pe__bundle_needs_remote_name(replica->remote, data_set)) {
925 
926  /* REMOTE_CONTAINER_HACK: Allow remote nodes to run containers that
927  * run pacemaker-remoted inside, without needing a separate IP for
928  * the container. This is done by configuring the inner remote's
929  * connection host as the magic string "#uname", then
930  * replacing it with the underlying host when needed.
931  */
932  xmlNode *nvpair = get_xpath_object("//nvpair[@name='" XML_RSC_ATTR_REMOTE_RA_ADDR "']",
933  replica->remote->xml, LOG_ERR);
934  const char *calculated_addr = NULL;
935 
936  // Replace the value in replica->remote->xml (if appropriate)
937  calculated_addr = pe__add_bundle_remote_name(replica->remote,
938  data_set,
939  nvpair, "value");
940  if (calculated_addr) {
941  /* Since this is for the bundle as a resource, and not any
942  * particular action, replace the value in the default
943  * parameters (not evaluated for node). action2xml() will grab
944  * it from there to replace it in node-evaluated parameters.
945  */
946  GHashTable *params = pe_rsc_params(replica->remote,
947  NULL, data_set);
948 
949  crm_trace("Set address for bundle connection %s to bundle host %s",
950  replica->remote->id, calculated_addr);
951  g_hash_table_replace(params,
953  strdup(calculated_addr));
954  } else {
955  /* The only way to get here is if the remote connection is
956  * neither currently running nor scheduled to run. That means we
957  * won't be doing any operations that require addr (only start
958  * requires it; we additionally use it to compare digests when
959  * unpacking status, promote, and migrate_from history, but
960  * that's already happened by this point).
961  */
962  crm_info("Unable to determine address for bundle %s remote connection",
963  rsc->id);
964  }
965  }
966  if (replica->ip) {
967  replica->ip->cmds->expand(replica->ip, data_set);
968  }
969  if (replica->container) {
970  replica->container->cmds->expand(replica->container, data_set);
971  }
972  if (replica->remote) {
973  replica->remote->cmds->expand(replica->remote, data_set);
974  }
975  }
976 }
977 
978 gboolean
980  pe_action_t *complete, gboolean force,
981  pe_working_set_t * data_set)
982 {
983  bool any_created = FALSE;
984  pe__bundle_variant_data_t *bundle_data = NULL;
985 
986  CRM_CHECK(rsc != NULL, return FALSE);
987 
988  get_bundle_variant_data(bundle_data, rsc);
989  for (GList *gIter = bundle_data->replicas; gIter != NULL;
990  gIter = gIter->next) {
991  pe__bundle_replica_t *replica = gIter->data;
992 
993  CRM_ASSERT(replica);
994  if (replica->ip) {
995  any_created |= replica->ip->cmds->create_probe(replica->ip, node,
996  complete, force,
997  data_set);
998  }
999  if (replica->child && (node->details == replica->node->details)) {
1000  any_created |= replica->child->cmds->create_probe(replica->child,
1001  node, complete,
1002  force, data_set);
1003  }
1004  if (replica->container) {
1005  bool created = replica->container->cmds->create_probe(replica->container,
1006  node, complete,
1007  force, data_set);
1008 
1009  if(created) {
1010  any_created = TRUE;
1011  /* If we're limited to one replica per host (due to
1012  * the lack of an IP range probably), then we don't
1013  * want any of our peer containers starting until
1014  * we've established that no other copies are already
1015  * running.
1016  *
1017  * Partly this is to ensure that nreplicas_per_host is
1018  * observed, but also to ensure that the containers
1019  * don't fail to start because the necessary port
1020  * mappings (which won't include an IP for uniqueness)
1021  * are already taken
1022  */
1023 
1024  for (GList *tIter = bundle_data->replicas;
1025  tIter && (bundle_data->nreplicas_per_host == 1);
1026  tIter = tIter->next) {
1027  pe__bundle_replica_t *other = tIter->data;
1028 
1029  if ((other != replica) && (other != NULL)
1030  && (other->container != NULL)) {
1031 
1032  custom_action_order(replica->container,
1033  pcmk__op_key(replica->container->id, RSC_STATUS, 0),
1034  NULL, other->container,
1035  pcmk__op_key(other->container->id, RSC_START, 0),
1036  NULL,
1038  data_set);
1039  }
1040  }
1041  }
1042  }
1043  if (replica->container && replica->remote
1044  && replica->remote->cmds->create_probe(replica->remote, node,
1045  complete, force,
1046  data_set)) {
1047 
1048  /* Do not probe the remote resource until we know where the
1049  * container is running. This is required for REMOTE_CONTAINER_HACK
1050  * to correctly probe remote resources.
1051  */
1052  char *probe_uuid = pcmk__op_key(replica->remote->id, RSC_STATUS,
1053  0);
1054  pe_action_t *probe = find_first_action(replica->remote->actions,
1055  probe_uuid, NULL, node);
1056 
1057  free(probe_uuid);
1058  if (probe) {
1059  any_created = TRUE;
1060  crm_trace("Ordering %s probe on %s",
1061  replica->remote->id, node->details->uname);
1062  custom_action_order(replica->container,
1063  pcmk__op_key(replica->container->id, RSC_START, 0),
1064  NULL, replica->remote, NULL, probe,
1065  pe_order_probe, data_set);
1066  }
1067  }
1068  }
1069  return any_created;
1070 }
1071 
1072 void
1074 {
1075 }
1076 
1077 void
1079 {
1080  pe__bundle_variant_data_t *bundle_data = NULL;
1081 
1082  CRM_CHECK(rsc != NULL, return);
1083 
1084  get_bundle_variant_data(bundle_data, rsc);
1085  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1086  gIter = gIter->next) {
1087  pe__bundle_replica_t *replica = gIter->data;
1088 
1089  CRM_ASSERT(replica);
1090  if (replica->ip) {
1091  LogActions(replica->ip, data_set);
1092  }
1093  if (replica->container) {
1094  LogActions(replica->container, data_set);
1095  }
1096  if (replica->remote) {
1097  LogActions(replica->remote, data_set);
1098  }
1099  if (replica->child) {
1100  LogActions(replica->child, data_set);
1101  }
1102  }
1103 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
enum rsc_role_e role_filter
Definition: internal.h:171
void pcmk__bundle_log_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
const char * task2text(enum action_tasks task)
Definition: common.c:406
#define RSC_STOP
Definition: crm.h:204
bool is_set_recursive(pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:363
#define crm_notice(fmt, args...)
Definition: logging.h:352
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition: remote.c:41
enum pe_action_flags pcmk__bundle_action_flags(pe_action_t *action, pe_node_t *node)
pe_resource_t * rsc_lh
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:19
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:99
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:371
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
GList * sort_nodes_by_weight(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
int priority
Definition: pe_types.h:407
pe_resource_t * container
Definition: pe_types.h:379
GList * children
Definition: pe_types.h:376
resource_alloc_functions_t * cmds
Definition: pe_types.h:332
void pcmk__new_colocation(const char *id, const char *node_attr, int score, pe_resource_t *rsc_lh, pe_resource_t *rsc_rh, const char *state_lh, const char *state_rh, bool influence, pe_working_set_t *data_set)
enum pe_action_flags(* action_flags)(pe_action_t *, pe_node_t *)
pe_resource_t * rsc
Definition: pe_types.h:409
gint sort_clone_instance(gconstpointer a, gconstpointer b, gpointer data_set)
pe_resource_t * remote_rsc
Definition: pe_types.h:230
GHashTable * meta
Definition: pe_types.h:372
resource_object_functions_t * fns
Definition: pe_types.h:331
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, pe_node_t *node)
bool pe__bundle_needs_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: bundle.c:949
enum pe_graph_flags(* update_actions)(pe_action_t *, pe_action_t *, pe_node_t *, enum pe_action_flags, enum pe_action_flags, enum pe_ordering, pe_working_set_t *data_set)
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:161
enum pe_graph_flags native_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type, pe_working_set_t *data_set)
enum crm_ais_msg_types type
Definition: cpg.c:48
void native_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
#define RSC_START
Definition: crm.h:201
int migration_threshold
Definition: pe_types.h:343
pe_action_t * action
Definition: pe_types.h:533
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:535
gboolean is_child_compatible(pe_resource_t *child_rsc, pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
void pcmk__bundle_rsc_colocation_lh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
#define XML_RSC_ATTR_REMOTE_RA_ADDR
Definition: msg_xml.h:247
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:47
void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes, int max, int per_host_max, pe_working_set_t *data_set)
#define pe_rsc_provisional
Definition: pe_types.h:258
int weight
Definition: pe_types.h:241
#define crm_warn(fmt, args...)
Definition: logging.h:351
pe_action_flags
Definition: pe_types.h:291
#define order_stop_stop(rsc1, rsc2, type)
pe_action_t * create_pseudo_resource_op(pe_resource_t *rsc, const char *task, bool optional, bool runnable, pe_working_set_t *data_set)
#define crm_debug(fmt, args...)
Definition: logging.h:355
char * task
Definition: pe_types.h:413
gboolean update_action(pe_action_t *action, pe_working_set_t *data_set)
int custom_action_order(pe_resource_t *lh_rsc, char *lh_task, pe_action_t *lh_action, pe_resource_t *rh_rsc, char *rh_task, pe_action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set)
#define crm_trace(fmt, args...)
Definition: logging.h:356
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: utils.c:1399
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
void promote_demote_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
struct pe_node_shared_s * details
Definition: pe_types.h:244
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:1802
unsigned long long flags
Definition: pe_types.h:347
const char * uname
Definition: pe_types.h:209
#define pe_rsc_promotable
Definition: pe_types.h:256
GHashTable * pe_rsc_params(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:457
enum action_tasks clone_child_action(pe_action_t *action)
void LogActions(pe_resource_t *rsc, pe_working_set_t *data_set)
bool assign_node(pe_resource_t *rsc, pe_node_t *node, gboolean force)
#define pe__set_graph_flags(graph_flags, gr_action, flags_to_set)
Definition: internal.h:125
GList * actions
Definition: pe_types.h:358
pe_graph_flags
Definition: pe_types.h:283
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:228
char * uuid
Definition: pe_types.h:414
#define pe_rsc_allocating
Definition: pe_types.h:259
pe_node_t * pcmk__bundle_allocate(pe_resource_t *rsc, pe_node_t *preferred, pe_working_set_t *data_set)
enum pe_obj_types variant
Definition: pe_types.h:329
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:953
void pcmk__bundle_rsc_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
int new_rsc_order(pe_resource_t *lh_rsc, const char *lh_task, pe_resource_t *rh_rsc, const char *rh_task, enum pe_ordering type, pe_working_set_t *data_set)
#define RSC_DEMOTED
Definition: crm.h:210
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:45
const char * pe__add_bundle_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set, xmlNode *xml, const char *field)
Definition: bundle.c:967
gboolean pcmk__bundle_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
void clone_create_pseudo_actions(pe_resource_t *rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify, pe_working_set_t *data_set)
pe_resource_t * find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current, pe_working_set_t *data_set)
#define RSC_STARTED
Definition: crm.h:202
void pcmk__bundle_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
#define crm_err(fmt, args...)
Definition: logging.h:350
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:215
#define RSC_PROMOTE
Definition: crm.h:207
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:53
void pcmk__bundle_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
#define pe_rsc_block
Definition: pe_types.h:250
enum pe_action_flags flags
Definition: pe_types.h:418
#define pe_rsc_failure_ignored
Definition: pe_types.h:275
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:54
#define order_start_start(rsc1, rsc2, type)
#define RSC_STOPPED
Definition: crm.h:205
#define RSC_PROMOTED
Definition: crm.h:208
gboolean crm_is_true(const char *s)
Definition: strings.c:415
pe_resource_t * find_compatible_child_by_node(pe_resource_t *local_child, pe_node_t *local_node, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:20
unsigned long long flags
Definition: pe_types.h:146
#define pe_err(fmt...)
Definition: internal.h:22
#define XML_RSC_ATTR_INTERLEAVE
Definition: msg_xml.h:224
#define pe_flag_show_scores
Definition: pe_types.h:133
void pcmk__bundle_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
#define crm_info(fmt, args...)
Definition: logging.h:353
#define pe_rsc_orphan
Definition: pe_types.h:248
enum pe_graph_flags pcmk__multi_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type, pe_working_set_t *data_set)
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition: utils.c:1422
void pcmk__bundle_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
void pcmk__bundle_append_meta(pe_resource_t *rsc, xmlNode *xml)
void(* rsc_colocation_lh)(pe_resource_t *, pe_resource_t *, pcmk__colocation_t *, pe_working_set_t *)
pe_ordering
Definition: pe_types.h:482
uint64_t flags
Definition: remote.c:149
int pe_get_failcount(pe_node_t *node, pe_resource_t *rsc, time_t *last_failure, uint32_t flags, xmlNode *xml_op, pe_working_set_t *data_set)
Definition: failcounts.c:251
action_tasks
Definition: common.h:62
int copies_per_node(pe_resource_t *rsc)
#define RSC_DEMOTE
Definition: crm.h:209
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:18
char * id
Definition: pe_types.h:320
GHashTable * allowed_nodes
Definition: pe_types.h:367