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