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