pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
clone.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <stdint.h>
13 
14 #include <crm/pengine/rules.h>
15 #include <crm/pengine/status.h>
16 #include <crm/pengine/internal.h>
17 #include <pe_status_private.h>
18 #include <crm/common/xml.h>
19 #include <crm/common/output.h>
22 
23 typedef struct clone_variant_data_s {
24  int clone_max;
25  int clone_node_max;
26 
27  int promoted_max;
28  int promoted_node_max;
29 
30  int total_clones;
31 
32  uint32_t flags; // Group of enum pcmk__clone_flags
33 
34  notify_data_t *stop_notify;
35  notify_data_t *start_notify;
36  notify_data_t *demote_notify;
37  notify_data_t *promote_notify;
38 
39  xmlNode *xml_obj_child;
41 
42 #define get_clone_variant_data(data, rsc) do { \
43  pcmk__assert(pcmk__is_clone(rsc)); \
44  data = rsc->priv->variant_opaque; \
45  } while (0)
46 
55 int
57 {
58  const clone_variant_data_t *clone_data = NULL;
59 
60  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
61  return clone_data->clone_max;
62 }
63 
72 int
74 {
75  const clone_variant_data_t *clone_data = NULL;
76 
77  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
78  return clone_data->clone_node_max;
79 }
80 
89 int
91 {
92  clone_variant_data_t *clone_data = NULL;
93 
94  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
95  return clone_data->promoted_max;
96 }
97 
106 int
108 {
109  clone_variant_data_t *clone_data = NULL;
110 
111  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
112  return clone_data->promoted_node_max;
113 }
114 
115 static GList *
116 sorted_hash_table_values(GHashTable *table)
117 {
118  GList *retval = NULL;
119  GHashTableIter iter;
120  gpointer key, value;
121 
122  g_hash_table_iter_init(&iter, table);
123  while (g_hash_table_iter_next(&iter, &key, &value)) {
124  if (!g_list_find_custom(retval, value, (GCompareFunc) strcmp)) {
125  retval = g_list_prepend(retval, (char *) value);
126  }
127  }
128 
129  retval = g_list_sort(retval, (GCompareFunc) strcmp);
130  return retval;
131 }
132 
133 static GList *
134 nodes_with_status(GHashTable *table, const char *status)
135 {
136  GList *retval = NULL;
137  GHashTableIter iter;
138  gpointer key, value;
139 
140  g_hash_table_iter_init(&iter, table);
141  while (g_hash_table_iter_next(&iter, &key, &value)) {
142  if (!strcmp((char *) value, status)) {
143  retval = g_list_prepend(retval, key);
144  }
145  }
146 
147  retval = g_list_sort(retval, (GCompareFunc) pcmk__numeric_strcasecmp);
148  return retval;
149 }
150 
151 static GString *
152 node_list_to_str(const GList *list)
153 {
154  GString *retval = NULL;
155 
156  for (const GList *iter = list; iter != NULL; iter = iter->next) {
157  pcmk__add_word(&retval, 1024, (const char *) iter->data);
158  }
159 
160  return retval;
161 }
162 
163 static void
164 clone_header(pcmk__output_t *out, int *rc, const pcmk_resource_t *rsc,
165  clone_variant_data_t *clone_data, const char *desc)
166 {
167  GString *attrs = NULL;
168 
170  pcmk__add_separated_word(&attrs, 64, "promotable", ", ");
171  }
172 
173  if (pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
174  pcmk__add_separated_word(&attrs, 64, "unique", ", ");
175  }
176 
177  if (pe__resource_is_disabled(rsc)) {
178  pcmk__add_separated_word(&attrs, 64, "disabled", ", ");
179  }
180 
182  pcmk__add_separated_word(&attrs, 64, "maintenance", ", ");
183 
184  } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
185  pcmk__add_separated_word(&attrs, 64, "unmanaged", ", ");
186  }
187 
188  if (attrs != NULL) {
189  PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s] (%s)%s%s%s",
190  rsc->id,
191  pcmk__xe_id(clone_data->xml_obj_child),
192  (const char *) attrs->str, desc ? " (" : "",
193  desc ? desc : "", desc ? ")" : "");
194  g_string_free(attrs, TRUE);
195  } else {
196  PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]%s%s%s",
197  rsc->id,
198  pcmk__xe_id(clone_data->xml_obj_child),
199  desc ? " (" : "", desc ? desc : "",
200  desc ? ")" : "");
201  }
202 }
203 
204 void
205 pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid,
207 {
208  if (pcmk__is_clone(rsc)) {
209  clone_variant_data_t *clone_data = rsc->priv->variant_opaque;
210 
211  pcmk__config_warn("Ignoring " PCMK_META_GLOBALLY_UNIQUE " for %s "
212  "because %s resources such as %s can be used only as "
213  "anonymous clones", rsc->id, standard, rid);
214 
215  clone_data->clone_node_max = 1;
216  clone_data->clone_max = QB_MIN(clone_data->clone_max,
217  g_list_length(scheduler->nodes));
218  }
219 }
220 
223 {
224  gboolean as_orphan = FALSE;
225  char *inc_num = NULL;
226  char *inc_max = NULL;
227  pcmk_resource_t *child_rsc = NULL;
228  xmlNode *child_copy = NULL;
229  clone_variant_data_t *clone_data = NULL;
230 
231  get_clone_variant_data(clone_data, rsc);
232 
233  CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
234 
235  if (clone_data->total_clones >= clone_data->clone_max) {
236  // If we've already used all available instances, this is an orphan
237  as_orphan = TRUE;
238  }
239 
240  // Allocate instance numbers in numerical order (starting at 0)
241  inc_num = pcmk__itoa(clone_data->total_clones);
242  inc_max = pcmk__itoa(clone_data->clone_max);
243 
244  child_copy = pcmk__xml_copy(NULL, clone_data->xml_obj_child);
245 
246  crm_xml_add(child_copy, PCMK__META_CLONE, inc_num);
247 
248  if (pe__unpack_resource(child_copy, &child_rsc, rsc,
249  scheduler) != pcmk_rc_ok) {
250  goto bail;
251  }
252 /* child_rsc->globally_unique = rsc->globally_unique; */
253 
254  pcmk__assert(child_rsc != NULL);
255  clone_data->total_clones += 1;
256  pcmk__rsc_trace(child_rsc, "Setting clone attributes for: %s",
257  child_rsc->id);
258  rsc->priv->children = g_list_append(rsc->priv->children, child_rsc);
259  if (as_orphan) {
261  }
262 
263  pcmk__insert_meta(child_rsc->priv, PCMK_META_CLONE_MAX, inc_max);
264  pcmk__rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
265 
266  bail:
267  free(inc_num);
268  free(inc_max);
269 
270  return child_rsc;
271 }
272 
286 static int
287 unpack_meta_int(const pcmk_resource_t *rsc, const char *meta_name,
288  const char *deprecated_name, int default_value)
289 {
290  int integer = default_value;
291  const char *value = g_hash_table_lookup(rsc->priv->meta, meta_name);
292 
293  if ((value == NULL) && (deprecated_name != NULL)) {
294  value = g_hash_table_lookup(rsc->priv->meta, deprecated_name);
295 
296  if (value != NULL) {
297  if (pcmk__str_eq(deprecated_name, PCMK__META_PROMOTED_MAX_LEGACY,
298  pcmk__str_none)) {
300  "Support for the " PCMK__META_PROMOTED_MAX_LEGACY
301  " meta-attribute (such as in %s) is deprecated "
302  "and will be removed in a future release. Use the "
303  PCMK_META_PROMOTED_MAX " meta-attribute instead.",
304  rsc->id);
305  } else if (pcmk__str_eq(deprecated_name, PCMK__META_PROMOTED_NODE_MAX_LEGACY,
306  pcmk__str_none)) {
308  "Support for the " PCMK__META_PROMOTED_NODE_MAX_LEGACY
309  " meta-attribute (such as in %s) is deprecated "
310  "and will be removed in a future release. Use the "
311  PCMK_META_PROMOTED_NODE_MAX " meta-attribute instead.",
312  rsc->id);
313  }
314  }
315  }
316  if (value != NULL) {
317  pcmk__scan_min_int(value, &integer, 0);
318  }
319  return integer;
320 }
321 
322 gboolean
324 {
325  int lpc = 0;
326  xmlNode *a_child = NULL;
327  xmlNode *xml_obj = rsc->priv->xml;
328  clone_variant_data_t *clone_data = NULL;
329 
330  pcmk__rsc_trace(rsc, "Processing resource %s...", rsc->id);
331 
332  clone_data = pcmk__assert_alloc(1, sizeof(clone_variant_data_t));
333  rsc->priv->variant_opaque = clone_data;
334 
336  // Use 1 as default but 0 for minimum and invalid
337  // @COMPAT PCMK__META_PROMOTED_MAX_LEGACY deprecated since 2.0.0
338  clone_data->promoted_max =
339  unpack_meta_int(rsc, PCMK_META_PROMOTED_MAX,
341 
342  // Use 1 as default but 0 for minimum and invalid
343  // @COMPAT PCMK__META_PROMOTED_NODE_MAX_LEGACY deprecated since 2.0.0
344  clone_data->promoted_node_max =
345  unpack_meta_int(rsc, PCMK_META_PROMOTED_NODE_MAX,
347  }
348 
349  // Use 1 as default but 0 for minimum and invalid
350  clone_data->clone_node_max = unpack_meta_int(rsc, PCMK_META_CLONE_NODE_MAX,
351  NULL, 1);
352 
353  /* Use number of nodes (but always at least 1, which is handy for crm_verify
354  * for a CIB without nodes) as default, but 0 for minimum and invalid
355  */
356  clone_data->clone_max = unpack_meta_int(rsc, PCMK_META_CLONE_MAX, NULL,
357  QB_MAX(1, g_list_length(scheduler->nodes)));
358 
359  if (crm_is_true(g_hash_table_lookup(rsc->priv->meta,
360  PCMK_META_ORDERED))) {
361  clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
362  "Clone", rsc->id,
363  clone_data->flags,
365  "pcmk__clone_ordered");
366  }
367 
369  && (clone_data->clone_node_max > 1)) {
370 
371  pcmk__config_err("Ignoring " PCMK_META_CLONE_NODE_MAX " of %d for %s "
372  "because anonymous clones support only one instance "
373  "per node", clone_data->clone_node_max, rsc->id);
374  clone_data->clone_node_max = 1;
375  }
376 
377  pcmk__rsc_trace(rsc, "Options for %s", rsc->id);
378  pcmk__rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
379  pcmk__rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
380  pcmk__rsc_trace(rsc, "\tClone is unique: %s",
381  pcmk__flag_text(rsc->flags, pcmk__rsc_unique));
382  pcmk__rsc_trace(rsc, "\tClone is promotable: %s",
383  pcmk__flag_text(rsc->flags, pcmk__rsc_promotable));
384 
385  // Clones may contain a single group or primitive
386  for (a_child = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
387  a_child != NULL; a_child = pcmk__xe_next(a_child, NULL)) {
388 
389  if (pcmk__str_any_of((const char *) a_child->name,
391  clone_data->xml_obj_child = a_child;
392  break;
393  }
394  }
395 
396  if (clone_data->xml_obj_child == NULL) {
397  pcmk__config_err("%s has nothing to clone", rsc->id);
398  return FALSE;
399  }
400 
401  /*
402  * Make clones ever so slightly sticky by default
403  *
404  * This helps ensure clone instances are not shuffled around the cluster
405  * for no benefit in situations when pre-allocation is not appropriate
406  */
407  if (g_hash_table_lookup(rsc->priv->meta,
410  }
411 
412  /* This ensures that the PCMK_META_GLOBALLY_UNIQUE value always exists for
413  * children to inherit when being unpacked, as well as in resource agents'
414  * environment.
415  */
417  pcmk__flag_text(rsc->flags, pcmk__rsc_unique));
418 
419  if (clone_data->clone_max <= 0) {
420  /* Create one child instance so that unpack_find_resource() will hook up
421  * any orphans up to the parent correctly.
422  */
423  if (pe__create_clone_child(rsc, scheduler) == NULL) {
424  return FALSE;
425  }
426 
427  } else {
428  // Create a child instance for each available instance number
429  for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
430  if (pe__create_clone_child(rsc, scheduler) == NULL) {
431  return FALSE;
432  }
433  }
434  }
435 
436  pcmk__rsc_trace(rsc, "Added %d children to resource %s...",
437  clone_data->clone_max, rsc->id);
438  return TRUE;
439 }
440 
441 gboolean
442 clone_active(pcmk_resource_t * rsc, gboolean all)
443 {
444  for (GList *gIter = rsc->priv->children;
445  gIter != NULL; gIter = gIter->next) {
446 
447  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
448  gboolean child_active = child_rsc->priv->fns->active(child_rsc, all);
449 
450  if (all == FALSE && child_active) {
451  return TRUE;
452  } else if (all && child_active == FALSE) {
453  return FALSE;
454  }
455  }
456 
457  if (all) {
458  return TRUE;
459  } else {
460  return FALSE;
461  }
462 }
463 
464 static const char *
465 configured_role_str(pcmk_resource_t * rsc)
466 {
467  const char *target_role = g_hash_table_lookup(rsc->priv->meta,
469 
470  if ((target_role == NULL) && (rsc->priv->children != NULL)) {
471  // Any instance will do
472  pcmk_resource_t *instance = rsc->priv->children->data;
473 
474  target_role = g_hash_table_lookup(instance->priv->meta,
476  }
477  return target_role;
478 }
479 
480 static enum rsc_role_e
481 configured_role(pcmk_resource_t *rsc)
482 {
483  enum rsc_role_e role = pcmk_role_unknown;
484  const char *target_role = configured_role_str(rsc);
485 
486  if (target_role != NULL) {
487  role = pcmk_parse_role(target_role);
488  if (role == pcmk_role_unknown) {
490  " for resource %s", rsc->id);
491  }
492  }
493  return role;
494 }
495 
496 bool
497 is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
498 {
499  bool all = !any;
500 
501  if (pcmk_is_set(rsc->flags, flag)) {
502  if(any) {
503  return TRUE;
504  }
505  } else if(all) {
506  return FALSE;
507  }
508 
509  for (GList *gIter = rsc->priv->children;
510  gIter != NULL; gIter = gIter->next) {
511 
512  if(is_set_recursive(gIter->data, flag, any)) {
513  if(any) {
514  return TRUE;
515  }
516 
517  } else if(all) {
518  return FALSE;
519  }
520  }
521 
522  if(all) {
523  return TRUE;
524  }
525  return FALSE;
526 }
527 
528 PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
529  "GList *")
530 int
531 pe__clone_xml(pcmk__output_t *out, va_list args)
532 {
533  uint32_t show_opts = va_arg(args, uint32_t);
534  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
535  GList *only_node = va_arg(args, GList *);
536  GList *only_rsc = va_arg(args, GList *);
537 
538  GList *all = NULL;
539  int rc = pcmk_rc_no_output;
540  gboolean printed_header = FALSE;
541  gboolean print_everything = TRUE;
542 
543  if (rsc->priv->fns->is_filtered(rsc, only_rsc, TRUE)) {
544  return rc;
545  }
546 
547  print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
548  (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
549 
550  all = g_list_prepend(all, (gpointer) "*");
551 
552  for (GList *gIter = rsc->priv->children;
553  gIter != NULL; gIter = gIter->next) {
554 
555  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
556 
557  if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
558  continue;
559  }
560 
561  if (child_rsc->priv->fns->is_filtered(child_rsc, only_rsc,
562  print_everything)) {
563  continue;
564  }
565 
566  if (!printed_header) {
567  const char *multi_state = pcmk__flag_text(rsc->flags,
569  const char *unique = pcmk__flag_text(rsc->flags, pcmk__rsc_unique);
570  const char *maintenance = pcmk__flag_text(rsc->flags,
572  const char *managed = pcmk__flag_text(rsc->flags,
574  const char *disabled = pcmk__btoa(pe__resource_is_disabled(rsc));
575  const char *failed = pcmk__flag_text(rsc->flags, pcmk__rsc_failed);
576  const char *ignored = pcmk__flag_text(rsc->flags,
578  const char *target_role = configured_role_str(rsc);
579  const char *desc = pe__resource_description(rsc, show_opts);
580 
581  printed_header = TRUE;
582 
583  rc = pe__name_and_nvpairs_xml(out, true, PCMK_XE_CLONE,
584  PCMK_XA_ID, rsc->id,
585  PCMK_XA_MULTI_STATE, multi_state,
586  PCMK_XA_UNIQUE, unique,
587  PCMK_XA_MAINTENANCE, maintenance,
588  PCMK_XA_MANAGED, managed,
589  PCMK_XA_DISABLED, disabled,
590  PCMK_XA_FAILED, failed,
591  PCMK_XA_FAILURE_IGNORED, ignored,
592  PCMK_XA_TARGET_ROLE, target_role,
593  PCMK_XA_DESCRIPTION, desc,
594  NULL);
595  pcmk__assert(rc == pcmk_rc_ok);
596  }
597 
598  out->message(out, (const char *) child_rsc->priv->xml->name,
599  show_opts, child_rsc, only_node, all);
600  }
601 
602  if (printed_header) {
604  }
605 
606  g_list_free(all);
607  return rc;
608 }
609 
610 PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
611  "GList *")
612 int
613 pe__clone_default(pcmk__output_t *out, va_list args)
614 {
615  uint32_t show_opts = va_arg(args, uint32_t);
616  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
617  GList *only_node = va_arg(args, GList *);
618  GList *only_rsc = va_arg(args, GList *);
619 
620  GHashTable *stopped = NULL;
621 
622  GString *list_text = NULL;
623 
624  GList *promoted_list = NULL;
625  GList *started_list = NULL;
626  GList *gIter = NULL;
627 
628  const char *desc = NULL;
629 
630  clone_variant_data_t *clone_data = NULL;
631  int active_instances = 0;
632  int rc = pcmk_rc_no_output;
633  gboolean print_everything = TRUE;
634 
635  desc = pe__resource_description(rsc, show_opts);
636 
637  get_clone_variant_data(clone_data, rsc);
638 
639  if (rsc->priv->fns->is_filtered(rsc, only_rsc, TRUE)) {
640  return rc;
641  }
642 
643  print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
644  (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
645 
646  for (gIter = rsc->priv->children; gIter != NULL; gIter = gIter->next) {
647  gboolean print_full = FALSE;
648  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
649  gboolean partially_active = child_rsc->priv->fns->active(child_rsc,
650  FALSE);
651 
652  if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
653  continue;
654  }
655 
656  if (child_rsc->priv->fns->is_filtered(child_rsc, only_rsc,
657  print_everything)) {
658  continue;
659  }
660 
661  if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
662  print_full = TRUE;
663  }
664 
665  if (pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
666  // Print individual instance when unique (except stopped orphans)
667  if (partially_active
668  || !pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
669  print_full = TRUE;
670  }
671 
672  // Everything else in this block is for anonymous clones
673 
674  } else if (pcmk_is_set(show_opts, pcmk_show_pending)
675  && (child_rsc->priv->pending_action != NULL)
676  && (strcmp(child_rsc->priv->pending_action,
677  "probe") != 0)) {
678  // Print individual instance when non-probe action is pending
679  print_full = TRUE;
680 
681  } else if (partially_active == FALSE) {
682  // List stopped instances when requested (except orphans)
683  if (!pcmk_is_set(child_rsc->flags, pcmk__rsc_removed)
684  && !pcmk_is_set(show_opts, pcmk_show_clone_detail)
685  && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
686  if (stopped == NULL) {
687  stopped = pcmk__strkey_table(free, free);
688  }
689  pcmk__insert_dup(stopped, child_rsc->id, "Stopped");
690  }
691 
692  } else if (is_set_recursive(child_rsc, pcmk__rsc_removed, TRUE)
693  || !is_set_recursive(child_rsc, pcmk__rsc_managed, FALSE)
694  || is_set_recursive(child_rsc, pcmk__rsc_failed, TRUE)) {
695 
696  // Print individual instance when active orphaned/unmanaged/failed
697  print_full = TRUE;
698 
699  } else if (child_rsc->priv->fns->active(child_rsc, TRUE)) {
700  // Instance of fully active anonymous clone
701 
702  pcmk_node_t *location = NULL;
703 
704  location = child_rsc->priv->fns->location(child_rsc, NULL,
706  if (location) {
707  // Instance is active on a single node
708 
709  enum rsc_role_e a_role;
710 
711  a_role = child_rsc->priv->fns->state(child_rsc, TRUE);
712 
713  if (location->details->online == FALSE && location->details->unclean) {
714  print_full = TRUE;
715 
716  } else if (a_role > pcmk_role_unpromoted) {
717  promoted_list = g_list_append(promoted_list, location);
718 
719  } else {
720  started_list = g_list_append(started_list, location);
721  }
722 
723  } else {
724  /* uncolocated group - bleh */
725  print_full = TRUE;
726  }
727 
728  } else {
729  // Instance of partially active anonymous clone
730  print_full = TRUE;
731  }
732 
733  if (print_full) {
734  GList *all = NULL;
735 
736  clone_header(out, &rc, rsc, clone_data, desc);
737 
738  /* Print every resource that's a child of this clone. */
739  all = g_list_prepend(all, (gpointer) "*");
740  out->message(out, (const char *) child_rsc->priv->xml->name,
741  show_opts, child_rsc, only_node, all);
742  g_list_free(all);
743  }
744  }
745 
746  if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
747  PCMK__OUTPUT_LIST_FOOTER(out, rc);
748  return pcmk_rc_ok;
749  }
750 
751  /* Promoted */
752  promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
753  for (gIter = promoted_list; gIter; gIter = gIter->next) {
754  pcmk_node_t *host = gIter->data;
755 
756  if (!pcmk__str_in_list(host->priv->name, only_node,
758  continue;
759  }
760 
761  pcmk__add_word(&list_text, 1024, host->priv->name);
762  active_instances++;
763  }
764  g_list_free(promoted_list);
765 
766  if ((list_text != NULL) && (list_text->len > 0)) {
767  clone_header(out, &rc, rsc, clone_data, desc);
768 
769  out->list_item(out, NULL, PCMK_ROLE_PROMOTED ": [ %s ]",
770  (const char *) list_text->str);
771  g_string_truncate(list_text, 0);
772  }
773 
774  /* Started/Unpromoted */
775  started_list = g_list_sort(started_list, pe__cmp_node_name);
776  for (gIter = started_list; gIter; gIter = gIter->next) {
777  pcmk_node_t *host = gIter->data;
778 
779  if (!pcmk__str_in_list(host->priv->name, only_node,
781  continue;
782  }
783 
784  pcmk__add_word(&list_text, 1024, host->priv->name);
785  active_instances++;
786  }
787  g_list_free(started_list);
788 
789  if ((list_text != NULL) && (list_text->len > 0)) {
790  clone_header(out, &rc, rsc, clone_data, desc);
791 
793  enum rsc_role_e role = configured_role(rsc);
794 
795  if (role == pcmk_role_unpromoted) {
796  out->list_item(out, NULL,
798  " (" PCMK_META_TARGET_ROLE "): [ %s ]",
799  (const char *) list_text->str);
800  } else {
801  out->list_item(out, NULL, PCMK_ROLE_UNPROMOTED ": [ %s ]",
802  (const char *) list_text->str);
803  }
804 
805  } else {
806  out->list_item(out, NULL, "Started: [ %s ]",
807  (const char *) list_text->str);
808  }
809  }
810 
811  if (list_text != NULL) {
812  g_string_free(list_text, TRUE);
813  }
814 
815  if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
817  && (clone_data->clone_max > active_instances)) {
818 
819  GList *nIter;
820  GList *list = g_hash_table_get_values(rsc->priv->allowed_nodes);
821 
822  /* Custom stopped table for non-unique clones */
823  if (stopped != NULL) {
824  g_hash_table_destroy(stopped);
825  stopped = NULL;
826  }
827 
828  if (list == NULL) {
829  /* Clusters with PCMK_OPT_SYMMETRIC_CLUSTER=false haven't
830  * calculated allowed nodes yet. If we've not probed for them
831  * yet, the Stopped list will be empty.
832  */
833  list = g_hash_table_get_values(rsc->priv->probed_nodes);
834  }
835 
836  list = g_list_sort(list, pe__cmp_node_name);
837  for (nIter = list; nIter != NULL; nIter = nIter->next) {
838  pcmk_node_t *node = (pcmk_node_t *) nIter->data;
839 
841  node->priv->name) == NULL)
842  && pcmk__str_in_list(node->priv->name, only_node,
844 
845  xmlNode *probe_op = NULL;
846  const char *state = "Stopped";
847 
848  if (configured_role(rsc) == pcmk_role_stopped) {
849  state = "Stopped (disabled)";
850  }
851 
852  if (stopped == NULL) {
853  stopped = pcmk__strkey_table(free, free);
854  }
855 
856  probe_op = pe__failed_probe_for_rsc(rsc,
857  node->priv->name);
858  if (probe_op != NULL) {
859  int rc;
860 
863  &rc, 0);
864  g_hash_table_insert(stopped, strdup(node->priv->name),
865  crm_strdup_printf("Stopped (%s)",
866  crm_exit_str(rc)));
867  } else {
868  pcmk__insert_dup(stopped, node->priv->name, state);
869  }
870  }
871  }
872  g_list_free(list);
873  }
874 
875  if (stopped != NULL) {
876  GList *list = sorted_hash_table_values(stopped);
877 
878  clone_header(out, &rc, rsc, clone_data, desc);
879 
880  for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
881  const char *status = status_iter->data;
882  GList *nodes = nodes_with_status(stopped, status);
883  GString *nodes_str = node_list_to_str(nodes);
884 
885  if (nodes_str != NULL) {
886  if (nodes_str->len > 0) {
887  out->list_item(out, NULL, "%s: [ %s ]", status,
888  (const char *) nodes_str->str);
889  }
890  g_string_free(nodes_str, TRUE);
891  }
892 
893  g_list_free(nodes);
894  }
895 
896  g_list_free(list);
897  g_hash_table_destroy(stopped);
898 
899  /* If there are no instances of this clone (perhaps because there are no
900  * nodes configured), simply output the clone header by itself. This can
901  * come up in PCS testing.
902  */
903  } else if (active_instances == 0) {
904  clone_header(out, &rc, rsc, clone_data, desc);
905  PCMK__OUTPUT_LIST_FOOTER(out, rc);
906  return rc;
907  }
908  }
909 
910  PCMK__OUTPUT_LIST_FOOTER(out, rc);
911  return rc;
912 }
913 
914 void
916 {
917  clone_variant_data_t *clone_data = NULL;
918 
919  get_clone_variant_data(clone_data, rsc);
920 
921  pcmk__rsc_trace(rsc, "Freeing %s", rsc->id);
922 
923  for (GList *gIter = rsc->priv->children;
924  gIter != NULL; gIter = gIter->next) {
925 
926  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
927 
928  pcmk__assert(child_rsc != NULL);
929  pcmk__rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
930  pcmk__xml_free(child_rsc->priv->xml);
931  child_rsc->priv->xml = NULL;
932  /* There could be a saved unexpanded xml */
933  pcmk__xml_free(child_rsc->priv->orig_xml);
934  child_rsc->priv->orig_xml = NULL;
935  child_rsc->priv->fns->free(child_rsc);
936  }
937 
938  g_list_free(rsc->priv->children);
939 
940  if (clone_data) {
941  pcmk__assert((clone_data->demote_notify == NULL)
942  && (clone_data->stop_notify == NULL)
943  && (clone_data->start_notify == NULL)
944  && (clone_data->promote_notify == NULL));
945  }
946 
947  common_free(rsc);
948 }
949 
950 enum rsc_role_e
951 clone_resource_state(const pcmk_resource_t * rsc, gboolean current)
952 {
953  enum rsc_role_e clone_role = pcmk_role_unknown;
954 
955  for (GList *gIter = rsc->priv->children;
956  gIter != NULL; gIter = gIter->next) {
957 
958  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
959  enum rsc_role_e a_role = child_rsc->priv->fns->state(child_rsc,
960  current);
961 
962  if (a_role > clone_role) {
963  clone_role = a_role;
964  }
965  }
966 
967  pcmk__rsc_trace(rsc, "%s role: %s", rsc->id, pcmk_role_text(clone_role));
968  return clone_role;
969 }
970 
978 bool
981 {
982  if (pcmk__is_clone(rsc)) {
983  clone_variant_data_t *clone_data = rsc->priv->variant_opaque;
984 
985  if (clone_data->clone_max == g_list_length(scheduler->nodes)) {
986  return TRUE;
987  }
988  }
989  return FALSE;
990 }
991 
992 gboolean
993 pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc,
994  gboolean check_parent)
995 {
996  gboolean passes = FALSE;
997  clone_variant_data_t *clone_data = NULL;
998 
1000  passes = TRUE;
1001  } else {
1002  get_clone_variant_data(clone_data, rsc);
1003  passes = pcmk__str_in_list(pcmk__xe_id(clone_data->xml_obj_child),
1004  only_rsc, pcmk__str_star_matches);
1005 
1006  if (!passes) {
1007  for (const GList *iter = rsc->priv->children;
1008  iter != NULL; iter = iter->next) {
1009 
1010  const pcmk_resource_t *child_rsc = NULL;
1011 
1012  child_rsc = (const pcmk_resource_t *) iter->data;
1013  if (!child_rsc->priv->fns->is_filtered(child_rsc, only_rsc,
1014  FALSE)) {
1015  passes = TRUE;
1016  break;
1017  }
1018  }
1019  }
1020  }
1021  return !passes;
1022 }
1023 
1024 const char *
1026 {
1027  clone_variant_data_t *clone_data = NULL;
1028  get_clone_variant_data(clone_data, rsc);
1029  return pcmk__xe_id(clone_data->xml_obj_child);
1030 }
1031 
1040 bool
1042 {
1043  clone_variant_data_t *clone_data = NULL;
1044 
1045  get_clone_variant_data(clone_data, clone);
1046  return pcmk_is_set(clone_data->flags, pcmk__clone_ordered);
1047 }
1048 
1059 int
1061 {
1062  clone_variant_data_t *clone_data = NULL;
1063 
1064  get_clone_variant_data(clone_data, clone);
1065  if (pcmk_is_set(clone_data->flags, flag)) {
1066  return pcmk_rc_already;
1067  }
1068  clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
1069  "Clone", clone->id,
1070  clone_data->flags, flag, "flag");
1071  return pcmk_rc_ok;
1072 }
1073 
1083 bool
1085 {
1086  clone_variant_data_t *clone_data = NULL;
1087 
1088  get_clone_variant_data(clone_data, clone);
1089  pcmk__assert(clone_data != NULL);
1090 
1091  return pcmk_all_flags_set(clone_data->flags, flags);
1092 }
1093 
1102 void
1104  bool any_demoting)
1105 {
1106  pcmk_action_t *action = NULL;
1107  pcmk_action_t *action_complete = NULL;
1108  clone_variant_data_t *clone_data = NULL;
1109 
1110  get_clone_variant_data(clone_data, clone);
1111 
1112  // Create a "promote" action for the clone itself
1114  !any_promoting, true);
1115 
1116  // Create a "promoted" action for when all promotions are done
1117  action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_PROMOTED,
1118  !any_promoting, true);
1119  action_complete->priority = PCMK_SCORE_INFINITY;
1120 
1121  // Create notification pseudo-actions for promotion
1122  if (clone_data->promote_notify == NULL) {
1123  clone_data->promote_notify = pe__action_notif_pseudo_ops(clone,
1125  action,
1126  action_complete);
1127  }
1128 
1129  // Create a "demote" action for the clone itself
1131  !any_demoting, true);
1132 
1133  // Create a "demoted" action for when all demotions are done
1134  action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_DEMOTED,
1135  !any_demoting, true);
1136  action_complete->priority = PCMK_SCORE_INFINITY;
1137 
1138  // Create notification pseudo-actions for demotion
1139  if (clone_data->demote_notify == NULL) {
1140  clone_data->demote_notify = pe__action_notif_pseudo_ops(clone,
1142  action,
1143  action_complete);
1144 
1145  if (clone_data->promote_notify != NULL) {
1146  order_actions(clone_data->stop_notify->post_done,
1147  clone_data->promote_notify->pre, pcmk__ar_ordered);
1148  order_actions(clone_data->start_notify->post_done,
1149  clone_data->promote_notify->pre, pcmk__ar_ordered);
1150  order_actions(clone_data->demote_notify->post_done,
1151  clone_data->promote_notify->pre, pcmk__ar_ordered);
1152  order_actions(clone_data->demote_notify->post_done,
1153  clone_data->start_notify->pre, pcmk__ar_ordered);
1154  order_actions(clone_data->demote_notify->post_done,
1155  clone_data->stop_notify->pre, pcmk__ar_ordered);
1156  }
1157  }
1158 }
1159 
1166 void
1168 {
1169  clone_variant_data_t *clone_data = NULL;
1170 
1171  get_clone_variant_data(clone_data, clone);
1172 
1173  pe__create_action_notifications(clone, clone_data->start_notify);
1174  pe__create_action_notifications(clone, clone_data->stop_notify);
1175  pe__create_action_notifications(clone, clone_data->promote_notify);
1176  pe__create_action_notifications(clone, clone_data->demote_notify);
1177 }
1178 
1185 void
1187 {
1188  clone_variant_data_t *clone_data = NULL;
1189 
1190  get_clone_variant_data(clone_data, clone);
1191 
1192  pe__free_action_notification_data(clone_data->demote_notify);
1193  clone_data->demote_notify = NULL;
1194 
1195  pe__free_action_notification_data(clone_data->stop_notify);
1196  clone_data->stop_notify = NULL;
1197 
1198  pe__free_action_notification_data(clone_data->start_notify);
1199  clone_data->start_notify = NULL;
1200 
1201  pe__free_action_notification_data(clone_data->promote_notify);
1202  clone_data->promote_notify = NULL;
1203 }
1204 
1215 void
1217  pcmk_action_t *start, pcmk_action_t *started,
1218  pcmk_action_t *stop, pcmk_action_t *stopped)
1219 {
1220  clone_variant_data_t *clone_data = NULL;
1221 
1222  get_clone_variant_data(clone_data, clone);
1223 
1224  if (clone_data->start_notify == NULL) {
1225  clone_data->start_notify = pe__action_notif_pseudo_ops(clone,
1227  start, started);
1228  }
1229 
1230  if (clone_data->stop_notify == NULL) {
1231  clone_data->stop_notify = pe__action_notif_pseudo_ops(clone,
1233  stop, stopped);
1234  if ((clone_data->start_notify != NULL)
1235  && (clone_data->stop_notify != NULL)) {
1236  order_actions(clone_data->stop_notify->post_done,
1237  clone_data->start_notify->pre, pcmk__ar_ordered);
1238  }
1239  }
1240 }
1241 
1250 unsigned int
1252 {
1253  const clone_variant_data_t *clone_data = NULL;
1254 
1255  get_clone_variant_data(clone_data, rsc);
1256  return clone_data->clone_node_max;
1257 }
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition: complex.c:1043
bool pe__clone_is_ordered(const pcmk_resource_t *clone)
Definition: clone.c:1041
#define LOG_TRACE
Definition: logging.h:38
pcmk__cpg_host_t host
Definition: cpg.c:52
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition: roles.c:23
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
Definition: clone.c:1251
#define PCMK_XA_MANAGED
Definition: xml_names.h:323
Control output from tools.
gboolean(* active)(pcmk_resource_t *rsc, gboolean all)
#define PCMK__XA_RC_CODE
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:116
Stopped.
Definition: roles.h:36
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
Definition: clone.c:497
#define PCMK_XE_PRIMITIVE
Definition: xml_names.h:164
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:149
xmlNode * pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
Definition: utils.c:882
bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler)
Definition: clone.c:979
#define pcmk__config_warn(fmt...)
void pe__create_clone_notifications(pcmk_resource_t *clone)
Definition: clone.c:1167
#define pcmk__rsc_trace(rsc, fmt, args...)
gboolean(* is_filtered)(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
void pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid, pcmk_scheduler_t *scheduler)
Definition: clone.c:205
pcmk_resource_t * pe__create_clone_child(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition: clone.c:222
gboolean clone_active(pcmk_resource_t *rsc, gboolean all)
Definition: clone.c:442
#define pcmk__insert_meta(obj, name, value)
#define pcmk__config_err(fmt...)
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
Definition: pe_output.c:22
#define PCMK_XA_FAILURE_IGNORED
Definition: xml_names.h:284
int pe__clone_default(pcmk__output_t *out, va_list args)
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, uint32_t target)
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:796
gboolean unclean
Definition: nodes.h:58
pcmk__clone_flags
#define PCMK__META_CLONE
#define PCMK_META_CLONE_MAX
Definition: options.h:82
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition: utils.c:563
const pcmk__rsc_methods_t * fns
void pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
Definition: utils.c:597
void clone_free(pcmk_resource_t *rsc)
Definition: clone.c:915
struct clone_variant_data_s clone_variant_data_t
gboolean clone_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition: clone.c:323
#define PCMK_XA_TARGET_ROLE
Definition: xml_names.h:422
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
Definition: complex.c:700
const char * action
Definition: pcmk_fence.c:32
#define PCMK_XA_DISABLED
Definition: xml_names.h:265
enum rsc_role_e pcmk_parse_role(const char *role)
Parse a resource role from a string role specification.
Definition: roles.c:51
#define PCMK_XA_FAILED
Definition: xml_names.h:283
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
pcmk__node_private_t * priv
Definition: nodes.h:85
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1750
int pe__clone_promoted_max(const pcmk_resource_t *clone)
Definition: clone.c:90
#define PCMK__META_PROMOTED_NODE_MAX_LEGACY
#define PCMK_XE_CLONE
Definition: xml_names.h:80
#define PCMK_META_GLOBALLY_UNIQUE
Definition: options.h:89
#define PCMK_ACTION_DEMOTE
Definition: actions.h:40
void common_free(pcmk_resource_t *rsc)
Definition: complex.c:1060
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:748
void pe__free_action_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:968
Actions are ordered (optionally, if no other flags are set)
pcmk_node_t * pcmk__find_node_in_list(const GList *nodes, const char *node_name)
Definition: nodes.c:170
#define PCMK_META_CLONE_NODE_MAX
Definition: options.h:84
void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting)
Definition: clone.c:1103
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name,...) G_GNUC_NULL_TERMINATED
Definition: pe_output.c:616
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define PCMK_XA_DESCRIPTION
Definition: xml_names.h:261
int pe__clone_xml(pcmk__output_t *out, va_list args)
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:951
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
#define PCMK_ACTION_START
Definition: actions.h:63
pcmk__resource_private_t * priv
Definition: resources.h:61
#define PCMK_META_RESOURCE_STICKINESS
Definition: options.h:111
Unpromoted.
Definition: roles.h:38
Wrappers for and extensions to libxml2.
rsc_role_e
Definition: roles.h:34
#define PCMK_META_TARGET_ROLE
Definition: options.h:113
#define PCMK__META_PROMOTED_MAX_LEGACY
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
#define PCMK_ACTION_STOP
Definition: actions.h:66
#define PCMK_XA_ID
Definition: xml_names.h:301
#define get_clone_variant_data(data, rsc)
Definition: clone.c:42
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1051
#define pcmk__warn_once(wo_flag, fmt...)
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:562
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
Definition: utils.c:465
#define PCMK_XA_MAINTENANCE
Definition: xml_names.h:321
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, gboolean current)
Definition: clone.c:951
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
Definition: xml_element.c:106
void pe__free_clone_notification_data(pcmk_resource_t *clone)
Definition: clone.c:1186
#define pcmk__assert(expr)
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
notify_data_t * pe__action_notif_pseudo_ops(pcmk_resource_t *rsc, const char *task, pcmk_action_t *action, pcmk_action_t *complete)
Definition: pe_notif.c:436
void pe__create_clone_notif_pseudo_ops(pcmk_resource_t *clone, pcmk_action_t *start, pcmk_action_t *started, pcmk_action_t *stop, pcmk_action_t *stopped)
Definition: clone.c:1216
int pe__clone_node_max(const pcmk_resource_t *clone)
Definition: clone.c:73
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
Cluster status and scheduling.
int pe__clone_max(const pcmk_resource_t *clone)
Definition: clone.c:56
GList * nodes
Definition: scheduler.h:97
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:685
int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag)
Definition: clone.c:1060
#define PCMK_ROLE_PROMOTED
Definition: roles.h:28
#define PCMK_XA_MULTI_STATE
Definition: xml_names.h:329
pcmk_scheduler_t * scheduler
#define PCMK_META_PROMOTED_NODE_MAX
Definition: options.h:103
const char * pe__clone_child_id(const pcmk_resource_t *rsc)
Definition: clone.c:1025
bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
Definition: utils.c:785
This structure contains everything that makes up a single output formatter.
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
Definition: utils.c:731
#define PCMK_ROLE_UNPROMOTED
Definition: roles.h:27
#define PCMK_ACTION_PROMOTE
Definition: actions.h:57
gboolean crm_is_true(const char *s)
Definition: strings.c:490
#define PCMK_XE_GROUP
Definition: xml_names.h:119
#define PCMK_META_PROMOTED_MAX
Definition: options.h:102
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1079
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition: clone.c:1084
unsigned long long flags
Definition: resources.h:69
gboolean pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition: clone.c:993
#define PCMK_ACTION_PROMOTED
Definition: actions.h:58
gboolean online
Definition: nodes.h:50
int pe__clone_promoted_node_max(const pcmk_resource_t *clone)
Definition: clone.c:107
Resource role is unknown.
Definition: roles.h:35
#define PCMK_META_ORDERED
Definition: options.h:99
void(* free)(pcmk_resource_t *rsc)
struct pcmk__node_details * details
Definition: nodes.h:82
#define PCMK_ACTION_DEMOTED
Definition: actions.h:41
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:703
#define PCMK_XA_UNIQUE
Definition: xml_names.h:434
uint64_t flags
Definition: remote.c:211
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition: scores.h:26
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:982