pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
clone.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2022 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/msg_xml.h>
19 #include <crm/common/output.h>
21 
22 #define VARIANT_CLONE 1
23 #include "./variant.h"
24 
25 #ifdef PCMK__COMPAT_2_0
26 #define PROMOTED_INSTANCES RSC_ROLE_PROMOTED_LEGACY_S "s"
27 #define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_LEGACY_S "s"
28 #else
29 #define PROMOTED_INSTANCES RSC_ROLE_PROMOTED_S
30 #define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_S
31 #endif
32 
41 int
43 {
44  clone_variant_data_t *clone_data = NULL;
45 
46  get_clone_variant_data(clone_data, uber_parent(clone));
47  return clone_data->promoted_max;
48 }
49 
58 int
60 {
61  clone_variant_data_t *clone_data = NULL;
62 
63  get_clone_variant_data(clone_data, uber_parent(clone));
64  return clone_data->promoted_node_max;
65 }
66 
67 static GList *
68 sorted_hash_table_values(GHashTable *table)
69 {
70  GList *retval = NULL;
71  GHashTableIter iter;
72  gpointer key, value;
73 
74  g_hash_table_iter_init(&iter, table);
75  while (g_hash_table_iter_next(&iter, &key, &value)) {
76  if (!g_list_find_custom(retval, value, (GCompareFunc) strcmp)) {
77  retval = g_list_prepend(retval, (char *) value);
78  }
79  }
80 
81  retval = g_list_sort(retval, (GCompareFunc) strcmp);
82  return retval;
83 }
84 
85 static GList *
86 nodes_with_status(GHashTable *table, const char *status)
87 {
88  GList *retval = NULL;
89  GHashTableIter iter;
90  gpointer key, value;
91 
92  g_hash_table_iter_init(&iter, table);
93  while (g_hash_table_iter_next(&iter, &key, &value)) {
94  if (!strcmp((char *) value, status)) {
95  retval = g_list_prepend(retval, key);
96  }
97  }
98 
99  retval = g_list_sort(retval, (GCompareFunc) pcmk__numeric_strcasecmp);
100  return retval;
101 }
102 
103 static GString *
104 node_list_to_str(const GList *list)
105 {
106  GString *retval = NULL;
107 
108  for (const GList *iter = list; iter != NULL; iter = iter->next) {
109  pcmk__add_word(&retval, 1024, (const char *) iter->data);
110  }
111 
112  return retval;
113 }
114 
115 static void
116 clone_header(pcmk__output_t *out, int *rc, pe_resource_t *rsc, clone_variant_data_t *clone_data)
117 {
118  GString *attrs = NULL;
119 
120  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
121  pcmk__add_separated_word(&attrs, 64, "promotable", ", ");
122  }
123 
124  if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
125  pcmk__add_separated_word(&attrs, 64, "unique", ", ");
126  }
127 
128  if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
129  pcmk__add_separated_word(&attrs, 64, "unmanaged", ", ");
130  }
131 
132  if (pe__resource_is_disabled(rsc)) {
133  pcmk__add_separated_word(&attrs, 64, "disabled", ", ");
134  }
135 
136  if (attrs != NULL) {
137  PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s] (%s)",
138  rsc->id, ID(clone_data->xml_obj_child),
139  (const char *) attrs->str);
140  g_string_free(attrs, TRUE);
141  } else {
142  PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]",
143  rsc->id, ID(clone_data->xml_obj_child))
144  }
145 }
146 
147 void
148 pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid,
150 {
151  if (pe_rsc_is_clone(rsc)) {
152  clone_variant_data_t *clone_data = NULL;
153 
154  get_clone_variant_data(clone_data, rsc);
155 
156  pe_warn("Ignoring " XML_RSC_ATTR_UNIQUE " for %s because %s resources "
157  "such as %s can be used only as anonymous clones",
158  rsc->id, standard, rid);
159 
160  clone_data->clone_node_max = 1;
161  clone_data->clone_max = QB_MIN(clone_data->clone_max,
162  g_list_length(data_set->nodes));
163  }
164 }
165 
168 {
169  char *child_id = NULL;
170  pe_resource_t *child = NULL;
171  const char *child_base = NULL;
172  clone_variant_data_t *clone_data = NULL;
173 
174  get_clone_variant_data(clone_data, rsc);
175 
176  child_base = ID(clone_data->xml_obj_child);
177  child_id = crm_strdup_printf("%s:%s", child_base, sub_id);
178  child = pe_find_resource(rsc->children, child_id);
179 
180  free(child_id);
181  return child;
182 }
183 
186 {
187  gboolean as_orphan = FALSE;
188  char *inc_num = NULL;
189  char *inc_max = NULL;
190  pe_resource_t *child_rsc = NULL;
191  xmlNode *child_copy = NULL;
192  clone_variant_data_t *clone_data = NULL;
193 
194  get_clone_variant_data(clone_data, rsc);
195 
196  CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
197 
198  if (clone_data->total_clones >= clone_data->clone_max) {
199  // If we've already used all available instances, this is an orphan
200  as_orphan = TRUE;
201  }
202 
203  // Allocate instance numbers in numerical order (starting at 0)
204  inc_num = pcmk__itoa(clone_data->total_clones);
205  inc_max = pcmk__itoa(clone_data->clone_max);
206 
207  child_copy = copy_xml(clone_data->xml_obj_child);
208 
209  crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
210 
211  if (pe__unpack_resource(child_copy, &child_rsc, rsc,
212  data_set) != pcmk_rc_ok) {
213  goto bail;
214  }
215 /* child_rsc->globally_unique = rsc->globally_unique; */
216 
217  CRM_ASSERT(child_rsc);
218  clone_data->total_clones += 1;
219  pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
220  rsc->children = g_list_append(rsc->children, child_rsc);
221  if (as_orphan) {
223  }
224 
225  add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max);
226  pe_rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
227 
228  bail:
229  free(inc_num);
230  free(inc_max);
231 
232  return child_rsc;
233 }
234 
235 gboolean
237 {
238  int lpc = 0;
239  xmlNode *a_child = NULL;
240  xmlNode *xml_obj = rsc->xml;
241  clone_variant_data_t *clone_data = NULL;
242 
243  const char *max_clones = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
244  const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
245 
246  pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
247 
248  clone_data = calloc(1, sizeof(clone_variant_data_t));
249  rsc->variant_opaque = clone_data;
250 
251  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
252  const char *promoted_max = NULL;
253  const char *promoted_node_max = NULL;
254 
255  promoted_max = g_hash_table_lookup(rsc->meta,
257  if (promoted_max == NULL) {
258  // @COMPAT deprecated since 2.0.0
259  promoted_max = g_hash_table_lookup(rsc->meta,
261  }
262 
263  promoted_node_max = g_hash_table_lookup(rsc->meta,
265  if (promoted_node_max == NULL) {
266  // @COMPAT deprecated since 2.0.0
267  promoted_node_max =
268  g_hash_table_lookup(rsc->meta,
270  }
271 
272  // Use 1 as default but 0 for minimum and invalid
273  if (promoted_max == NULL) {
274  clone_data->promoted_max = 1;
275  } else {
276  pcmk__scan_min_int(promoted_max, &(clone_data->promoted_max), 0);
277  }
278 
279  // Use 1 as default but 0 for minimum and invalid
280  if (promoted_node_max == NULL) {
281  clone_data->promoted_node_max = 1;
282  } else {
283  pcmk__scan_min_int(promoted_node_max,
284  &(clone_data->promoted_node_max), 0);
285  }
286  }
287 
288  // Implied by calloc()
289  /* clone_data->xml_obj_child = NULL; */
290 
291  // Use 1 as default but 0 for minimum and invalid
292  if (max_clones_node == NULL) {
293  clone_data->clone_node_max = 1;
294  } else {
295  pcmk__scan_min_int(max_clones_node, &(clone_data->clone_node_max), 0);
296  }
297 
298  /* Use number of nodes (but always at least 1, which is handy for crm_verify
299  * for a CIB without nodes) as default, but 0 for minimum and invalid
300  */
301  if (max_clones == NULL) {
302  clone_data->clone_max = QB_MAX(1, g_list_length(data_set->nodes));
303  } else {
304  pcmk__scan_min_int(max_clones, &(clone_data->clone_max), 0);
305  }
306 
307  if (crm_is_true(g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED))) {
308  clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
309  "Clone", rsc->id,
310  clone_data->flags,
312  "pe__clone_ordered");
313  }
314 
315  if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
316  pcmk__config_err("Ignoring " XML_RSC_ATTR_PROMOTED_MAX " for %s "
317  "because anonymous clones support only one instance "
318  "per node", rsc->id);
319  clone_data->clone_node_max = 1;
320  }
321 
322  pe_rsc_trace(rsc, "Options for %s", rsc->id);
323  pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
324  pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
325  pe_rsc_trace(rsc, "\tClone is unique: %s",
326  pe__rsc_bool_str(rsc, pe_rsc_unique));
327  pe_rsc_trace(rsc, "\tClone is promotable: %s",
328  pe__rsc_bool_str(rsc, pe_rsc_promotable));
329 
330  // Clones may contain a single group or primitive
331  for (a_child = pcmk__xe_first_child(xml_obj); a_child != NULL;
332  a_child = pcmk__xe_next(a_child)) {
333 
334  if (pcmk__str_any_of((const char *)a_child->name, XML_CIB_TAG_RESOURCE, XML_CIB_TAG_GROUP, NULL)) {
335  clone_data->xml_obj_child = a_child;
336  break;
337  }
338  }
339 
340  if (clone_data->xml_obj_child == NULL) {
341  pcmk__config_err("%s has nothing to clone", rsc->id);
342  return FALSE;
343  }
344 
345  /*
346  * Make clones ever so slightly sticky by default
347  *
348  * This helps ensure clone instances are not shuffled around the cluster
349  * for no benefit in situations when pre-allocation is not appropriate
350  */
351  if (g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
353  }
354 
355  /* This ensures that the globally-unique value always exists for children to
356  * inherit when being unpacked, as well as in resource agents' environment.
357  */
359  pe__rsc_bool_str(rsc, pe_rsc_unique));
360 
361  if (clone_data->clone_max <= 0) {
362  /* Create one child instance so that unpack_find_resource() will hook up
363  * any orphans up to the parent correctly.
364  */
365  if (pe__create_clone_child(rsc, data_set) == NULL) {
366  return FALSE;
367  }
368 
369  } else {
370  // Create a child instance for each available instance number
371  for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
372  if (pe__create_clone_child(rsc, data_set) == NULL) {
373  return FALSE;
374  }
375  }
376  }
377 
378  pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
379  return TRUE;
380 }
381 
382 gboolean
383 clone_active(pe_resource_t * rsc, gboolean all)
384 {
385  GList *gIter = rsc->children;
386 
387  for (; gIter != NULL; gIter = gIter->next) {
388  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
389  gboolean child_active = child_rsc->fns->active(child_rsc, all);
390 
391  if (all == FALSE && child_active) {
392  return TRUE;
393  } else if (all && child_active == FALSE) {
394  return FALSE;
395  }
396  }
397 
398  if (all) {
399  return TRUE;
400  } else {
401  return FALSE;
402  }
403 }
404 
409 static void
410 short_print(const char *list, const char *prefix, const char *type,
411  const char *suffix, long options, void *print_data)
412 {
413  if(suffix == NULL) {
414  suffix = "";
415  }
416 
417  if (!pcmk__str_empty(list)) {
418  if (options & pe_print_html) {
419  status_print("<li>");
420  }
421  status_print("%s%s: [ %s ]%s", prefix, type, list, suffix);
422 
423  if (options & pe_print_html) {
424  status_print("</li>\n");
425 
426  } else if (options & pe_print_suppres_nl) {
427  /* nothing */
428  } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
429  status_print("\n");
430  }
431 
432  }
433 }
434 
435 static const char *
436 configured_role_str(pe_resource_t * rsc)
437 {
438  const char *target_role = g_hash_table_lookup(rsc->meta,
440 
441  if ((target_role == NULL) && rsc->children && rsc->children->data) {
442  target_role = g_hash_table_lookup(((pe_resource_t*)rsc->children->data)->meta,
444  }
445  return target_role;
446 }
447 
448 static enum rsc_role_e
449 configured_role(pe_resource_t * rsc)
450 {
451  const char *target_role = configured_role_str(rsc);
452 
453  if (target_role) {
454  return text2role(target_role);
455  }
456  return RSC_ROLE_UNKNOWN;
457 }
458 
463 static void
464 clone_print_xml(pe_resource_t *rsc, const char *pre_text, long options,
465  void *print_data)
466 {
467  char *child_text = crm_strdup_printf("%s ", pre_text);
468  const char *target_role = configured_role_str(rsc);
469  GList *gIter = rsc->children;
470 
471  status_print("%s<clone ", pre_text);
472  status_print("id=\"%s\" ", rsc->id);
473  status_print("multi_state=\"%s\" ",
474  pe__rsc_bool_str(rsc, pe_rsc_promotable));
475  status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_unique));
476  status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
477  status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
478  status_print("failure_ignored=\"%s\" ",
479  pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
480  if (target_role) {
481  status_print("target_role=\"%s\" ", target_role);
482  }
483  status_print(">\n");
484 
485  for (; gIter != NULL; gIter = gIter->next) {
486  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
487 
488  child_rsc->fns->print(child_rsc, child_text, options, print_data);
489  }
490 
491  status_print("%s</clone>\n", pre_text);
492  free(child_text);
493 }
494 
495 bool
496 is_set_recursive(const pe_resource_t *rsc, long long flag, bool any)
497 {
498  GList *gIter;
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 (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
510  if(is_set_recursive(gIter->data, flag, any)) {
511  if(any) {
512  return TRUE;
513  }
514 
515  } else if(all) {
516  return FALSE;
517  }
518  }
519 
520  if(all) {
521  return TRUE;
522  }
523  return FALSE;
524 }
525 
530 void
531 clone_print(pe_resource_t *rsc, const char *pre_text, long options,
532  void *print_data)
533 {
534  GString *list_text = NULL;
535  char *child_text = NULL;
536  GString *stopped_list = NULL;
537 
538  GList *promoted_list = NULL;
539  GList *started_list = NULL;
540  GList *gIter = rsc->children;
541 
542  clone_variant_data_t *clone_data = NULL;
543  int active_instances = 0;
544 
545  if (pre_text == NULL) {
546  pre_text = " ";
547  }
548 
549  if (options & pe_print_xml) {
550  clone_print_xml(rsc, pre_text, options, print_data);
551  return;
552  }
553 
554  get_clone_variant_data(clone_data, rsc);
555 
556  child_text = crm_strdup_printf("%s ", pre_text);
557 
558  status_print("%sClone Set: %s [%s]%s%s%s",
559  pre_text ? pre_text : "", rsc->id, ID(clone_data->xml_obj_child),
560  pcmk_is_set(rsc->flags, pe_rsc_promotable)? " (promotable)" : "",
561  pcmk_is_set(rsc->flags, pe_rsc_unique)? " (unique)" : "",
562  pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : " (unmanaged)");
563 
564  if (options & pe_print_html) {
565  status_print("\n<ul>\n");
566 
567  } else if ((options & pe_print_log) == 0) {
568  status_print("\n");
569  }
570 
571  for (; gIter != NULL; gIter = gIter->next) {
572  gboolean print_full = FALSE;
573  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
574  gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
575 
576  if (options & pe_print_clone_details) {
577  print_full = TRUE;
578  }
579 
580  if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
581  // Print individual instance when unique (except stopped orphans)
582  if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
583  print_full = TRUE;
584  }
585 
586  // Everything else in this block is for anonymous clones
587 
588  } else if (pcmk_is_set(options, pe_print_pending)
589  && (child_rsc->pending_task != NULL)
590  && strcmp(child_rsc->pending_task, "probe")) {
591  // Print individual instance when non-probe action is pending
592  print_full = TRUE;
593 
594  } else if (partially_active == FALSE) {
595  // List stopped instances when requested (except orphans)
596  if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
597  && !pcmk_is_set(options, pe_print_clone_active)) {
598 
599  pcmk__add_word(&stopped_list, 1024, child_rsc->id);
600  }
601 
602  } else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
603  || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
604  || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
605 
606  // Print individual instance when active orphaned/unmanaged/failed
607  print_full = TRUE;
608 
609  } else if (child_rsc->fns->active(child_rsc, TRUE)) {
610  // Instance of fully active anonymous clone
611 
612  pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
613 
614  if (location) {
615  // Instance is active on a single node
616 
617  enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
618 
619  if (location->details->online == FALSE && location->details->unclean) {
620  print_full = TRUE;
621 
622  } else if (a_role > RSC_ROLE_UNPROMOTED) {
623  promoted_list = g_list_append(promoted_list, location);
624 
625  } else {
626  started_list = g_list_append(started_list, location);
627  }
628 
629  } else {
630  /* uncolocated group - bleh */
631  print_full = TRUE;
632  }
633 
634  } else {
635  // Instance of partially active anonymous clone
636  print_full = TRUE;
637  }
638 
639  if (print_full) {
640  if (options & pe_print_html) {
641  status_print("<li>\n");
642  }
643  child_rsc->fns->print(child_rsc, child_text, options, print_data);
644  if (options & pe_print_html) {
645  status_print("</li>\n");
646  }
647  }
648  }
649 
650  /* Promoted */
651  promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
652  for (gIter = promoted_list; gIter; gIter = gIter->next) {
653  pe_node_t *host = gIter->data;
654 
655  pcmk__add_word(&list_text, 1024, host->details->uname);
656  active_instances++;
657  }
658 
659  if (list_text != NULL) {
660  short_print((const char *) list_text->str, child_text,
661  PROMOTED_INSTANCES, NULL, options, print_data);
662  g_string_truncate(list_text, 0);
663  }
664  g_list_free(promoted_list);
665 
666  /* Started/Unpromoted */
667  started_list = g_list_sort(started_list, pe__cmp_node_name);
668  for (gIter = started_list; gIter; gIter = gIter->next) {
669  pe_node_t *host = gIter->data;
670 
671  pcmk__add_word(&list_text, 1024, host->details->uname);
672  active_instances++;
673  }
674 
675  if (list_text != NULL) {
676  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
677  enum rsc_role_e role = configured_role(rsc);
678 
679  if (role == RSC_ROLE_UNPROMOTED) {
680  short_print((const char *) list_text->str, child_text,
681  UNPROMOTED_INSTANCES " (target-role)", NULL,
682  options, print_data);
683  } else {
684  short_print((const char *) list_text->str, child_text,
685  UNPROMOTED_INSTANCES, NULL, options, print_data);
686  }
687 
688  } else {
689  short_print((const char *) list_text->str, child_text, "Started",
690  NULL, options, print_data);
691  }
692  }
693 
694  g_list_free(started_list);
695 
696  if (!pcmk_is_set(options, pe_print_clone_active)) {
697  const char *state = "Stopped";
698  enum rsc_role_e role = configured_role(rsc);
699 
700  if (role == RSC_ROLE_STOPPED) {
701  state = "Stopped (disabled)";
702  }
703 
704  if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
705  && (clone_data->clone_max > active_instances)) {
706 
707  GList *nIter;
708  GList *list = g_hash_table_get_values(rsc->allowed_nodes);
709 
710  /* Custom stopped list for non-unique clones */
711  if (stopped_list != NULL) {
712  g_string_truncate(stopped_list, 0);
713  }
714 
715  if (list == NULL) {
716  /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
717  * If we've not probed for them yet, the Stopped list will be empty
718  */
719  list = g_hash_table_get_values(rsc->known_on);
720  }
721 
722  list = g_list_sort(list, pe__cmp_node_name);
723  for (nIter = list; nIter != NULL; nIter = nIter->next) {
724  pe_node_t *node = (pe_node_t *)nIter->data;
725 
726  if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
727  pcmk__add_word(&stopped_list, 1024, node->details->uname);
728  }
729  }
730  g_list_free(list);
731  }
732 
733  if (stopped_list != NULL) {
734  short_print((const char *) stopped_list->str, child_text, state,
735  NULL, options, print_data);
736  }
737  }
738 
739  if (options & pe_print_html) {
740  status_print("</ul>\n");
741  }
742 
743  if (list_text != NULL) {
744  g_string_free(list_text, TRUE);
745  }
746 
747  if (stopped_list != NULL) {
748  g_string_free(stopped_list, TRUE);
749  }
750  free(child_text);
751 }
752 
753 PCMK__OUTPUT_ARGS("clone", "uint32_t", "pe_resource_t *", "GList *", "GList *")
754 int
755 pe__clone_xml(pcmk__output_t *out, va_list args)
756 {
757  uint32_t show_opts = va_arg(args, uint32_t);
758  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
759  GList *only_node = va_arg(args, GList *);
760  GList *only_rsc = va_arg(args, GList *);
761 
762  GList *gIter = rsc->children;
763  GList *all = NULL;
764  int rc = pcmk_rc_no_output;
765  gboolean printed_header = FALSE;
766  gboolean print_everything = TRUE;
767 
768  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
769  return rc;
770  }
771 
772  print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
773  (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
774 
775  all = g_list_prepend(all, (gpointer) "*");
776 
777  for (; gIter != NULL; gIter = gIter->next) {
778  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
779 
780  if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
781  continue;
782  }
783 
784  if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
785  continue;
786  }
787 
788  if (!printed_header) {
789  printed_header = TRUE;
790 
791  rc = pe__name_and_nvpairs_xml(out, true, "clone", 8,
792  "id", rsc->id,
793  "multi_state", pe__rsc_bool_str(rsc, pe_rsc_promotable),
794  "unique", pe__rsc_bool_str(rsc, pe_rsc_unique),
795  "managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
796  "disabled", pcmk__btoa(pe__resource_is_disabled(rsc)),
797  "failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
798  "failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
799  "target_role", configured_role_str(rsc));
800  CRM_ASSERT(rc == pcmk_rc_ok);
801  }
802 
803  out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
804  child_rsc, only_node, all);
805  }
806 
807  if (printed_header) {
809  }
810 
811  g_list_free(all);
812  return rc;
813 }
814 
815 PCMK__OUTPUT_ARGS("clone", "uint32_t", "pe_resource_t *", "GList *", "GList *")
816 int
818 {
819  uint32_t show_opts = va_arg(args, uint32_t);
820  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
821  GList *only_node = va_arg(args, GList *);
822  GList *only_rsc = va_arg(args, GList *);
823 
824  GHashTable *stopped = NULL;
825 
826  GString *list_text = NULL;
827 
828  GList *promoted_list = NULL;
829  GList *started_list = NULL;
830  GList *gIter = rsc->children;
831 
832  clone_variant_data_t *clone_data = NULL;
833  int active_instances = 0;
834  int rc = pcmk_rc_no_output;
835  gboolean print_everything = TRUE;
836 
837  get_clone_variant_data(clone_data, rsc);
838 
839  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
840  return rc;
841  }
842 
843  print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
844  (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
845 
846  for (; gIter != NULL; gIter = gIter->next) {
847  gboolean print_full = FALSE;
848  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
849  gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
850 
851  if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
852  continue;
853  }
854 
855  if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
856  continue;
857  }
858 
859  if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
860  print_full = TRUE;
861  }
862 
863  if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
864  // Print individual instance when unique (except stopped orphans)
865  if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
866  print_full = TRUE;
867  }
868 
869  // Everything else in this block is for anonymous clones
870 
871  } else if (pcmk_is_set(show_opts, pcmk_show_pending)
872  && (child_rsc->pending_task != NULL)
873  && strcmp(child_rsc->pending_task, "probe")) {
874  // Print individual instance when non-probe action is pending
875  print_full = TRUE;
876 
877  } else if (partially_active == FALSE) {
878  // List stopped instances when requested (except orphans)
879  if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
880  && !pcmk_is_set(show_opts, pcmk_show_clone_detail)
881  && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
882  if (stopped == NULL) {
883  stopped = pcmk__strkey_table(free, free);
884  }
885  g_hash_table_insert(stopped, strdup(child_rsc->id), strdup("Stopped"));
886  }
887 
888  } else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
889  || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
890  || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
891 
892  // Print individual instance when active orphaned/unmanaged/failed
893  print_full = TRUE;
894 
895  } else if (child_rsc->fns->active(child_rsc, TRUE)) {
896  // Instance of fully active anonymous clone
897 
898  pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
899 
900  if (location) {
901  // Instance is active on a single node
902 
903  enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
904 
905  if (location->details->online == FALSE && location->details->unclean) {
906  print_full = TRUE;
907 
908  } else if (a_role > RSC_ROLE_UNPROMOTED) {
909  promoted_list = g_list_append(promoted_list, location);
910 
911  } else {
912  started_list = g_list_append(started_list, location);
913  }
914 
915  } else {
916  /* uncolocated group - bleh */
917  print_full = TRUE;
918  }
919 
920  } else {
921  // Instance of partially active anonymous clone
922  print_full = TRUE;
923  }
924 
925  if (print_full) {
926  GList *all = NULL;
927 
928  clone_header(out, &rc, rsc, clone_data);
929 
930  /* Print every resource that's a child of this clone. */
931  all = g_list_prepend(all, (gpointer) "*");
932  out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
933  child_rsc, only_node, all);
934  g_list_free(all);
935  }
936  }
937 
938  if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
939  PCMK__OUTPUT_LIST_FOOTER(out, rc);
940  return pcmk_rc_ok;
941  }
942 
943  /* Promoted */
944  promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
945  for (gIter = promoted_list; gIter; gIter = gIter->next) {
946  pe_node_t *host = gIter->data;
947 
948  if (!pcmk__str_in_list(host->details->uname, only_node,
950  continue;
951  }
952 
953  pcmk__add_word(&list_text, 1024, host->details->uname);
954  active_instances++;
955  }
956  g_list_free(promoted_list);
957 
958  if ((list_text != NULL) && (list_text->len > 0)) {
959  clone_header(out, &rc, rsc, clone_data);
960 
961  out->list_item(out, NULL, PROMOTED_INSTANCES ": [ %s ]",
962  (const char *) list_text->str);
963  g_string_truncate(list_text, 0);
964  }
965 
966  /* Started/Unpromoted */
967  started_list = g_list_sort(started_list, pe__cmp_node_name);
968  for (gIter = started_list; gIter; gIter = gIter->next) {
969  pe_node_t *host = gIter->data;
970 
971  if (!pcmk__str_in_list(host->details->uname, only_node,
973  continue;
974  }
975 
976  pcmk__add_word(&list_text, 1024, host->details->uname);
977  active_instances++;
978  }
979  g_list_free(started_list);
980 
981  if ((list_text != NULL) && (list_text->len > 0)) {
982  clone_header(out, &rc, rsc, clone_data);
983 
984  if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
985  enum rsc_role_e role = configured_role(rsc);
986 
987  if (role == RSC_ROLE_UNPROMOTED) {
988  out->list_item(out, NULL,
989  UNPROMOTED_INSTANCES " (target-role): [ %s ]",
990  (const char *) list_text->str);
991  } else {
992  out->list_item(out, NULL, UNPROMOTED_INSTANCES ": [ %s ]",
993  (const char *) list_text->str);
994  }
995 
996  } else {
997  out->list_item(out, NULL, "Started: [ %s ]",
998  (const char *) list_text->str);
999  }
1000  }
1001 
1002  if (list_text != NULL) {
1003  g_string_free(list_text, TRUE);
1004  }
1005 
1006  if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1007  if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
1008  && (clone_data->clone_max > active_instances)) {
1009 
1010  GList *nIter;
1011  GList *list = g_hash_table_get_values(rsc->allowed_nodes);
1012 
1013  /* Custom stopped table for non-unique clones */
1014  if (stopped != NULL) {
1015  g_hash_table_destroy(stopped);
1016  stopped = NULL;
1017  }
1018 
1019  if (list == NULL) {
1020  /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
1021  * If we've not probed for them yet, the Stopped list will be empty
1022  */
1023  list = g_hash_table_get_values(rsc->known_on);
1024  }
1025 
1026  list = g_list_sort(list, pe__cmp_node_name);
1027  for (nIter = list; nIter != NULL; nIter = nIter->next) {
1028  pe_node_t *node = (pe_node_t *)nIter->data;
1029 
1030  if (pe_find_node(rsc->running_on, node->details->uname) == NULL &&
1031  pcmk__str_in_list(node->details->uname, only_node,
1033  xmlNode *probe_op = pe__failed_probe_for_rsc(rsc, node->details->uname);
1034  const char *state = "Stopped";
1035 
1036  if (configured_role(rsc) == RSC_ROLE_STOPPED) {
1037  state = "Stopped (disabled)";
1038  }
1039 
1040  if (stopped == NULL) {
1041  stopped = pcmk__strkey_table(free, free);
1042  }
1043  if (probe_op != NULL) {
1044  int rc;
1045 
1047  g_hash_table_insert(stopped, strdup(node->details->uname),
1048  crm_strdup_printf("Stopped (%s)", services_ocf_exitcode_str(rc)));
1049  } else {
1050  g_hash_table_insert(stopped, strdup(node->details->uname),
1051  strdup(state));
1052  }
1053  }
1054  }
1055  g_list_free(list);
1056  }
1057 
1058  if (stopped != NULL) {
1059  GList *list = sorted_hash_table_values(stopped);
1060 
1061  clone_header(out, &rc, rsc, clone_data);
1062 
1063  for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
1064  const char *status = status_iter->data;
1065  GList *nodes = nodes_with_status(stopped, status);
1066  GString *nodes_str = node_list_to_str(nodes);
1067 
1068  if (nodes_str != NULL) {
1069  if (nodes_str->len > 0) {
1070  out->list_item(out, NULL, "%s: [ %s ]", status,
1071  (const char *) nodes_str->str);
1072  }
1073  g_string_free(nodes_str, TRUE);
1074  }
1075 
1076  g_list_free(nodes);
1077  }
1078 
1079  g_list_free(list);
1080  g_hash_table_destroy(stopped);
1081 
1082  /* If there are no instances of this clone (perhaps because there are no
1083  * nodes configured), simply output the clone header by itself. This can
1084  * come up in PCS testing.
1085  */
1086  } else if (active_instances == 0) {
1087  clone_header(out, &rc, rsc, clone_data);
1088  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1089  return rc;
1090  }
1091  }
1092 
1093  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1094  return rc;
1095 }
1096 
1097 void
1099 {
1100  clone_variant_data_t *clone_data = NULL;
1101 
1102  get_clone_variant_data(clone_data, rsc);
1103 
1104  pe_rsc_trace(rsc, "Freeing %s", rsc->id);
1105 
1106  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1107  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1108 
1109  CRM_ASSERT(child_rsc);
1110  pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
1111  free_xml(child_rsc->xml);
1112  child_rsc->xml = NULL;
1113  /* There could be a saved unexpanded xml */
1114  free_xml(child_rsc->orig_xml);
1115  child_rsc->orig_xml = NULL;
1116  child_rsc->fns->free(child_rsc);
1117  }
1118 
1119  g_list_free(rsc->children);
1120 
1121  if (clone_data) {
1122  CRM_ASSERT(clone_data->demote_notify == NULL);
1123  CRM_ASSERT(clone_data->stop_notify == NULL);
1124  CRM_ASSERT(clone_data->start_notify == NULL);
1125  CRM_ASSERT(clone_data->promote_notify == NULL);
1126  }
1127 
1128  common_free(rsc);
1129 }
1130 
1131 enum rsc_role_e
1132 clone_resource_state(const pe_resource_t * rsc, gboolean current)
1133 {
1134  enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN;
1135  GList *gIter = rsc->children;
1136 
1137  for (; gIter != NULL; gIter = gIter->next) {
1138  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1139  enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
1140 
1141  if (a_role > clone_role) {
1142  clone_role = a_role;
1143  }
1144  }
1145 
1146  pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
1147  return clone_role;
1148 }
1149 
1157 bool
1160 {
1161  if (pe_rsc_is_clone(rsc)) {
1162  clone_variant_data_t *clone_data = NULL;
1163 
1164  get_clone_variant_data(clone_data, rsc);
1165  if (clone_data->clone_max == g_list_length(data_set->nodes)) {
1166  return TRUE;
1167  }
1168  }
1169  return FALSE;
1170 }
1171 
1172 gboolean
1173 pe__clone_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
1174 {
1175  gboolean passes = FALSE;
1176  clone_variant_data_t *clone_data = NULL;
1177 
1179  passes = TRUE;
1180  } else {
1181  get_clone_variant_data(clone_data, rsc);
1182  passes = pcmk__str_in_list(ID(clone_data->xml_obj_child), only_rsc, pcmk__str_star_matches);
1183 
1184  if (!passes) {
1185  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1186  pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1187 
1188  if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
1189  passes = TRUE;
1190  break;
1191  }
1192  }
1193  }
1194  }
1195 
1196  return !passes;
1197 }
1198 
1199 const char *
1201 {
1202  clone_variant_data_t *clone_data = NULL;
1203  get_clone_variant_data(clone_data, rsc);
1204  return ID(clone_data->xml_obj_child);
1205 }
1206 
1215 bool
1217 {
1218  clone_variant_data_t *clone_data = NULL;
1219 
1220  get_clone_variant_data(clone_data, clone);
1221  return pcmk_is_set(clone_data->flags, pe__clone_ordered);
1222 }
1223 
1234 int
1236 {
1237  clone_variant_data_t *clone_data = NULL;
1238 
1239  get_clone_variant_data(clone_data, clone);
1240  if (pcmk_is_set(clone_data->flags, flag)) {
1241  return pcmk_rc_already;
1242  }
1243  clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
1244  "Clone", clone->id,
1245  clone_data->flags, flag, "flag");
1246  return pcmk_rc_ok;
1247 }
1248 
1257 void
1259  bool any_demoting)
1260 {
1261  pe_action_t *action = NULL;
1262  pe_action_t *action_complete = NULL;
1263  clone_variant_data_t *clone_data = NULL;
1264 
1265  get_clone_variant_data(clone_data, clone);
1266 
1267  // Create a "promote" action for the clone itself
1268  action = pe__new_rsc_pseudo_action(clone, RSC_PROMOTE, !any_promoting,
1269  true);
1270 
1271  // Create a "promoted" action for when all promotions are done
1272  action_complete = pe__new_rsc_pseudo_action(clone, RSC_PROMOTED,
1273  !any_promoting, true);
1274  action_complete->priority = INFINITY;
1275 
1276  // Create notification pseudo-actions for promotion
1277  if (clone_data->promote_notify == NULL) {
1278  clone_data->promote_notify = pe__clone_notif_pseudo_ops(clone,
1279  RSC_PROMOTE,
1280  action,
1281  action_complete);
1282  }
1283 
1284  // Create a "demote" action for the clone itself
1285  action = pe__new_rsc_pseudo_action(clone, RSC_DEMOTE, !any_demoting, true);
1286 
1287  // Create a "demoted" action for when all demotions are done
1288  action_complete = pe__new_rsc_pseudo_action(clone, RSC_DEMOTED,
1289  !any_demoting, true);
1290  action_complete->priority = INFINITY;
1291 
1292  // Create notification pseudo-actions for demotion
1293  if (clone_data->demote_notify == NULL) {
1294  clone_data->demote_notify = pe__clone_notif_pseudo_ops(clone,
1295  RSC_DEMOTE,
1296  action,
1297  action_complete);
1298 
1299  if (clone_data->promote_notify != NULL) {
1300  order_actions(clone_data->stop_notify->post_done,
1301  clone_data->promote_notify->pre,
1303  order_actions(clone_data->start_notify->post_done,
1304  clone_data->promote_notify->pre,
1306  order_actions(clone_data->demote_notify->post_done,
1307  clone_data->promote_notify->pre,
1309  order_actions(clone_data->demote_notify->post_done,
1310  clone_data->start_notify->pre,
1312  order_actions(clone_data->demote_notify->post_done,
1313  clone_data->stop_notify->pre,
1315  }
1316  }
1317 }
#define LOG_TRACE
Definition: logging.h:37
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
pe_resource_t * find_clone_instance(pe_resource_t *rsc, const char *sub_id, pe_working_set_t *data_set)
Definition: clone.c:167
#define PCMK_XA_PROMOTED_MAX_LEGACY
Definition: msg_xml.h:49
pe_node_t * pe_find_node(GList *node_list, const char *uname)
Definition: status.c:443
xmlNode * orig_xml
Definition: pe_types.h:332
void clone_print(pe_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: clone.c:531
GHashTable * known_on
Definition: pe_types.h:374
#define INFINITY
Definition: crm.h:99
#define PROMOTED_INSTANCES
Definition: clone.c:29
Control output from tools.
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
int priority
Definition: pe_types.h:404
gboolean clone_unpack(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: clone.c:236
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:180
GList * children
Definition: pe_types.h:384
#define UNPROMOTED_INSTANCES
Definition: clone.c:30
xmlNode * xml
Definition: pe_types.h:331
#define XML_RSC_ATTR_INCARNATION
Definition: msg_xml.h:228
#define pcmk__config_err(fmt...)
bool pe__is_universal_clone(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: clone.c:1158
void pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid, pe_working_set_t *data_set)
Definition: clone.c:148
GHashTable * meta
Definition: pe_types.h:380
#define pe_rsc_unique
Definition: pe_types.h:262
resource_object_functions_t * fns
Definition: pe_types.h:340
bool pe__clone_is_ordered(pe_resource_t *clone)
Definition: clone.c:1216
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
int pe__clone_promoted_node_max(pe_resource_t *clone)
Definition: clone.c:59
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:703
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition: status.c:391
#define XML_RSC_ATTR_STICKINESS
Definition: msg_xml.h:239
const char * pe__clone_child_id(pe_resource_t *rsc)
Definition: clone.c:1200
pe_action_t * pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1647
enum crm_ais_msg_types type
Definition: cpg.c:48
enum rsc_role_e clone_resource_state(const pe_resource_t *rsc, gboolean current)
Definition: clone.c:1132
#define XML_RSC_ATTR_INCARNATION_MAX
Definition: msg_xml.h:229
char * pending_task
Definition: pe_types.h:353
gboolean pe__clone_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition: clone.c:1173
int pe__clone_xml(pcmk__output_t *out, va_list args)
Definition: clone.c:755
const char * action
Definition: pcmk_fence.c:30
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
Definition: msg_xml.h:50
GList * nodes
Definition: pe_types.h:164
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:891
void pe__set_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
Definition: utils.c:595
const char * role2text(enum rsc_role_e role)
Definition: common.c:454
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55
#define pe_warn(fmt...)
Definition: internal.h:54
#define pe_rsc_failed
Definition: pe_types.h:276
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:912
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
pe__clone_flags
Definition: internal.h:21
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:217
#define PCMK__OUTPUT_ARGS(ARGS...)
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name, size_t pairs_count,...)
Definition: pe_output.c:544
int pe__set_clone_flag(pe_resource_t *clone, enum pe__clone_flags flag)
Definition: clone.c:1235
void clone_free(pe_resource_t *rsc)
Definition: clone.c:1098
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
struct pe_node_shared_s * details
Definition: pe_types.h:252
bool is_set_recursive(const pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:496
void common_free(pe_resource_t *rsc)
Definition: complex.c:926
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:474
unsigned long long flags
Definition: pe_types.h:355
const char * uname
Definition: pe_types.h:216
#define pe_rsc_promotable
Definition: pe_types.h:264
#define XML_RSC_ATTR_ORDERED
Definition: msg_xml.h:226
pe_working_set_t * data_set
void(* print)(pe_resource_t *, const char *, long, void *)
Definition: pe_types.h:52
void pe__create_promotable_pseudo_ops(pe_resource_t *clone, bool any_promoting, bool any_demoting)
Definition: clone.c:1258
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:231
pe_resource_t * pe__create_clone_child(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: clone.c:185
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:236
void(* free)(pe_resource_t *)
Definition: pe_types.h:56
void free_xml(xmlNode *child)
Definition: xml.c:885
enum rsc_role_e text2role(const char *role)
Definition: common.c:483
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:952
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:513
#define RSC_DEMOTED
Definition: crm.h:208
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:237
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition: pe_types.h:54
#define XML_RSC_ATTR_PROMOTED_MAX
Definition: msg_xml.h:233
xmlNode * pe__failed_probe_for_rsc(pe_resource_t *rsc, const char *name)
Definition: utils.c:859
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
Cluster status and scheduling.
gboolean(* is_filtered)(pe_resource_t *, GList *, gboolean)
Definition: pe_types.h:58
bool pcmk__rsc_filtered_by_node(pe_resource_t *rsc, GList *only_node)
Definition: utils.c:768
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:504
void * variant_opaque
Definition: pe_types.h:339
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:568
#define RSC_PROMOTE
Definition: crm.h:205
#define status_print(fmt, args...)
This structure contains everything that makes up a single output formatter.
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1018
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
#define XML_RSC_ATTR_PROMOTED_NODEMAX
Definition: msg_xml.h:234
GList * running_on
Definition: pe_types.h:373
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:311
#define pe_rsc_failure_ignored
Definition: pe_types.h:289
#define RSC_PROMOTED
Definition: crm.h:206
gboolean clone_active(pe_resource_t *rsc, gboolean all)
Definition: clone.c:383
gboolean crm_is_true(const char *s)
Definition: strings.c:416
#define XML_CIB_TAG_GROUP
Definition: msg_xml.h:218
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
notify_data_t * pe__clone_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
Definition: pe_notif.c:428
bool pe__resource_is_disabled(pe_resource_t *rsc)
Definition: utils.c:735
#define ID(x)
Definition: msg_xml.h:468
gboolean unclean
Definition: pe_types.h:224
int pe__clone_promoted_max(pe_resource_t *clone)
Definition: clone.c:42
#define pe_rsc_managed
Definition: pe_types.h:257
#define pe_rsc_orphan
Definition: pe_types.h:256
gboolean online
Definition: pe_types.h:220
int pe__unpack_resource(xmlNode *xml_obj, pe_resource_t **rsc, pe_resource_t *parent, pe_working_set_t *data_set)
Definition: complex.c:562
#define RSC_DEMOTE
Definition: crm.h:207
gboolean(* active)(pe_resource_t *, gboolean)
Definition: pe_types.h:53
int pe__clone_default(pcmk__output_t *out, va_list args)
Definition: clone.c:817
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:883