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