pacemaker  2.1.7-0f7f88312f
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>
22 
23 #ifdef PCMK__COMPAT_2_0
24 #define PROMOTED_INSTANCES PCMK__ROLE_PROMOTED_LEGACY "s"
25 #define UNPROMOTED_INSTANCES PCMK__ROLE_UNPROMOTED_LEGACY "s"
26 #else
27 #define PROMOTED_INSTANCES PCMK__ROLE_PROMOTED
28 #define UNPROMOTED_INSTANCES PCMK__ROLE_UNPROMOTED
29 #endif
30 
31 typedef struct clone_variant_data_s {
32  int clone_max;
33  int clone_node_max;
34 
35  int promoted_max;
36  int promoted_node_max;
37 
38  int total_clones;
39 
40  uint32_t flags; // Group of enum pcmk__clone_flags
41 
42  notify_data_t *stop_notify;
43  notify_data_t *start_notify;
44  notify_data_t *demote_notify;
45  notify_data_t *promote_notify;
46 
47  xmlNode *xml_obj_child;
49 
50 #define get_clone_variant_data(data, rsc) \
51  CRM_ASSERT((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_clone)); \
52  data = (clone_variant_data_t *) rsc->variant_opaque;
53 
62 int
64 {
65  const clone_variant_data_t *clone_data = NULL;
66 
67  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
68  return clone_data->clone_max;
69 }
70 
79 int
81 {
82  const clone_variant_data_t *clone_data = NULL;
83 
84  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
85  return clone_data->clone_node_max;
86 }
87 
96 int
98 {
99  clone_variant_data_t *clone_data = NULL;
100 
101  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
102  return clone_data->promoted_max;
103 }
104 
113 int
115 {
116  clone_variant_data_t *clone_data = NULL;
117 
118  get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
119  return clone_data->promoted_node_max;
120 }
121 
122 static GList *
123 sorted_hash_table_values(GHashTable *table)
124 {
125  GList *retval = NULL;
126  GHashTableIter iter;
127  gpointer key, value;
128 
129  g_hash_table_iter_init(&iter, table);
130  while (g_hash_table_iter_next(&iter, &key, &value)) {
131  if (!g_list_find_custom(retval, value, (GCompareFunc) strcmp)) {
132  retval = g_list_prepend(retval, (char *) value);
133  }
134  }
135 
136  retval = g_list_sort(retval, (GCompareFunc) strcmp);
137  return retval;
138 }
139 
140 static GList *
141 nodes_with_status(GHashTable *table, const char *status)
142 {
143  GList *retval = NULL;
144  GHashTableIter iter;
145  gpointer key, value;
146 
147  g_hash_table_iter_init(&iter, table);
148  while (g_hash_table_iter_next(&iter, &key, &value)) {
149  if (!strcmp((char *) value, status)) {
150  retval = g_list_prepend(retval, key);
151  }
152  }
153 
154  retval = g_list_sort(retval, (GCompareFunc) pcmk__numeric_strcasecmp);
155  return retval;
156 }
157 
158 static GString *
159 node_list_to_str(const GList *list)
160 {
161  GString *retval = NULL;
162 
163  for (const GList *iter = list; iter != NULL; iter = iter->next) {
164  pcmk__add_word(&retval, 1024, (const char *) iter->data);
165  }
166 
167  return retval;
168 }
169 
170 static void
171 clone_header(pcmk__output_t *out, int *rc, const pcmk_resource_t *rsc,
172  clone_variant_data_t *clone_data, const char *desc)
173 {
174  GString *attrs = NULL;
175 
177  pcmk__add_separated_word(&attrs, 64, "promotable", ", ");
178  }
179 
180  if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
181  pcmk__add_separated_word(&attrs, 64, "unique", ", ");
182  }
183 
184  if (pe__resource_is_disabled(rsc)) {
185  pcmk__add_separated_word(&attrs, 64, "disabled", ", ");
186  }
187 
189  pcmk__add_separated_word(&attrs, 64, "maintenance", ", ");
190 
191  } else if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
192  pcmk__add_separated_word(&attrs, 64, "unmanaged", ", ");
193  }
194 
195  if (attrs != NULL) {
196  PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s] (%s)%s%s%s",
197  rsc->id, ID(clone_data->xml_obj_child),
198  (const char *) attrs->str, desc ? " (" : "",
199  desc ? desc : "", desc ? ")" : "");
200  g_string_free(attrs, TRUE);
201  } else {
202  PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]%s%s%s",
203  rsc->id, ID(clone_data->xml_obj_child),
204  desc ? " (" : "", desc ? desc : "",
205  desc ? ")" : "");
206  }
207 }
208 
209 void
210 pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid,
212 {
213  if (pe_rsc_is_clone(rsc)) {
214  clone_variant_data_t *clone_data = rsc->variant_opaque;
215 
216  pe_warn("Ignoring " XML_RSC_ATTR_UNIQUE " for %s because %s resources "
217  "such as %s can be used only as anonymous clones",
218  rsc->id, standard, rid);
219 
220  clone_data->clone_node_max = 1;
221  clone_data->clone_max = QB_MIN(clone_data->clone_max,
222  g_list_length(scheduler->nodes));
223  }
224 }
225 
227 find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
228 {
229  char *child_id = NULL;
230  pcmk_resource_t *child = NULL;
231  const char *child_base = NULL;
232  clone_variant_data_t *clone_data = NULL;
233 
234  get_clone_variant_data(clone_data, rsc);
235 
236  child_base = ID(clone_data->xml_obj_child);
237  child_id = crm_strdup_printf("%s:%s", child_base, sub_id);
238  child = pe_find_resource(rsc->children, child_id);
239 
240  free(child_id);
241  return child;
242 }
243 
246 {
247  gboolean as_orphan = FALSE;
248  char *inc_num = NULL;
249  char *inc_max = NULL;
250  pcmk_resource_t *child_rsc = NULL;
251  xmlNode *child_copy = NULL;
252  clone_variant_data_t *clone_data = NULL;
253 
254  get_clone_variant_data(clone_data, rsc);
255 
256  CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
257 
258  if (clone_data->total_clones >= clone_data->clone_max) {
259  // If we've already used all available instances, this is an orphan
260  as_orphan = TRUE;
261  }
262 
263  // Allocate instance numbers in numerical order (starting at 0)
264  inc_num = pcmk__itoa(clone_data->total_clones);
265  inc_max = pcmk__itoa(clone_data->clone_max);
266 
267  child_copy = copy_xml(clone_data->xml_obj_child);
268 
269  crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
270 
271  if (pe__unpack_resource(child_copy, &child_rsc, rsc,
272  scheduler) != pcmk_rc_ok) {
273  goto bail;
274  }
275 /* child_rsc->globally_unique = rsc->globally_unique; */
276 
277  CRM_ASSERT(child_rsc);
278  clone_data->total_clones += 1;
279  pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
280  rsc->children = g_list_append(rsc->children, child_rsc);
281  if (as_orphan) {
283  }
284 
285  add_hash_param(child_rsc->meta, PCMK_META_CLONE_MAX, inc_max);
286  pe_rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
287 
288  bail:
289  free(inc_num);
290  free(inc_max);
291 
292  return child_rsc;
293 }
294 
308 static int
309 unpack_meta_int(const pcmk_resource_t *rsc, const char *meta_name,
310  const char *deprecated_name, int default_value)
311 {
312  int integer = default_value;
313  const char *value = g_hash_table_lookup(rsc->meta, meta_name);
314 
315  if ((value == NULL) && (deprecated_name != NULL)) {
316  value = g_hash_table_lookup(rsc->meta, deprecated_name);
317  }
318  if (value != NULL) {
319  pcmk__scan_min_int(value, &integer, 0);
320  }
321  return integer;
322 }
323 
324 gboolean
326 {
327  int lpc = 0;
328  xmlNode *a_child = NULL;
329  xmlNode *xml_obj = rsc->xml;
330  clone_variant_data_t *clone_data = NULL;
331 
332  pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
333 
334  clone_data = calloc(1, sizeof(clone_variant_data_t));
335  rsc->variant_opaque = clone_data;
336 
338  // Use 1 as default but 0 for minimum and invalid
339  // @COMPAT PCMK_XA_PROMOTED_MAX_LEGACY deprecated since 2.0.0
340  clone_data->promoted_max = unpack_meta_int(rsc, PCMK_META_PROMOTED_MAX,
342  1);
343 
344  // Use 1 as default but 0 for minimum and invalid
345  // @COMPAT PCMK_XA_PROMOTED_NODE_MAX_LEGACY deprecated since 2.0.0
346  clone_data->promoted_node_max =
347  unpack_meta_int(rsc, PCMK_META_PROMOTED_NODE_MAX,
349  }
350 
351  // Implied by calloc()
352  /* clone_data->xml_obj_child = NULL; */
353 
354  // Use 1 as default but 0 for minimum and invalid
355  clone_data->clone_node_max = unpack_meta_int(rsc, PCMK_META_CLONE_NODE_MAX,
356  NULL, 1);
357 
358  /* Use number of nodes (but always at least 1, which is handy for crm_verify
359  * for a CIB without nodes) as default, but 0 for minimum and invalid
360  */
361  clone_data->clone_max = unpack_meta_int(rsc, PCMK_META_CLONE_MAX, NULL,
362  QB_MAX(1, g_list_length(scheduler->nodes)));
363 
364  if (crm_is_true(g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED))) {
365  clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
366  "Clone", rsc->id,
367  clone_data->flags,
369  "pcmk__clone_ordered");
370  }
371 
372  if (!pcmk_is_set(rsc->flags, pcmk_rsc_unique)
373  && (clone_data->clone_node_max > 1)) {
374 
375  pcmk__config_err("Ignoring " PCMK_META_CLONE_NODE_MAX " of %d for %s "
376  "because anonymous clones support only one instance "
377  "per node", clone_data->clone_node_max, 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, pcmk_rsc_unique));
386  pe_rsc_trace(rsc, "\tClone is promotable: %s",
387  pe__rsc_bool_str(rsc, pcmk_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, pcmk_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, scheduler) == 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, scheduler) == 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(pcmk_resource_t * rsc, gboolean all)
443 {
444  GList *gIter = rsc->children;
445 
446  for (; gIter != NULL; gIter = gIter->next) {
447  pcmk_resource_t *child_rsc = (pcmk_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(pcmk_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  pcmk_resource_t *instance = rsc->children->data; // Any instance will do
502 
503  target_role = g_hash_table_lookup(instance->meta,
505  }
506  return target_role;
507 }
508 
509 static enum rsc_role_e
510 configured_role(pcmk_resource_t *rsc)
511 {
512  const char *target_role = configured_role_str(rsc);
513 
514  if (target_role) {
515  return text2role(target_role);
516  }
517  return pcmk_role_unknown;
518 }
519 
524 static void
525 clone_print_xml(pcmk_resource_t *rsc, const char *pre_text, long options,
526  void *print_data)
527 {
528  char *child_text = crm_strdup_printf("%s ", pre_text);
529  const char *target_role = configured_role_str(rsc);
530  GList *gIter = rsc->children;
531 
532  status_print("%s<clone ", pre_text);
533  status_print(XML_ATTR_ID "=\"%s\" ", rsc->id);
534  status_print("multi_state=\"%s\" ",
535  pe__rsc_bool_str(rsc, pcmk_rsc_promotable));
536  status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pcmk_rsc_unique));
537  status_print("managed=\"%s\" ",
538  pe__rsc_bool_str(rsc, pcmk_rsc_managed));
539  status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pcmk_rsc_failed));
540  status_print("failure_ignored=\"%s\" ",
541  pe__rsc_bool_str(rsc, pcmk_rsc_ignore_failure));
542  if (target_role) {
543  status_print("target_role=\"%s\" ", target_role);
544  }
545  status_print(">\n");
546 
547  for (; gIter != NULL; gIter = gIter->next) {
548  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
549 
550  child_rsc->fns->print(child_rsc, child_text, options, print_data);
551  }
552 
553  status_print("%s</clone>\n", pre_text);
554  free(child_text);
555 }
556 
557 bool
558 is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
559 {
560  GList *gIter;
561  bool all = !any;
562 
563  if (pcmk_is_set(rsc->flags, flag)) {
564  if(any) {
565  return TRUE;
566  }
567  } else if(all) {
568  return FALSE;
569  }
570 
571  for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
572  if(is_set_recursive(gIter->data, flag, any)) {
573  if(any) {
574  return TRUE;
575  }
576 
577  } else if(all) {
578  return FALSE;
579  }
580  }
581 
582  if(all) {
583  return TRUE;
584  }
585  return FALSE;
586 }
587 
592 void
593 clone_print(pcmk_resource_t *rsc, const char *pre_text, long options,
594  void *print_data)
595 {
596  GString *list_text = NULL;
597  char *child_text = NULL;
598  GString *stopped_list = NULL;
599 
600  GList *promoted_list = NULL;
601  GList *started_list = NULL;
602  GList *gIter = rsc->children;
603 
604  clone_variant_data_t *clone_data = NULL;
605  int active_instances = 0;
606 
607  if (pre_text == NULL) {
608  pre_text = " ";
609  }
610 
611  if (options & pe_print_xml) {
612  clone_print_xml(rsc, pre_text, options, print_data);
613  return;
614  }
615 
616  get_clone_variant_data(clone_data, rsc);
617 
618  child_text = crm_strdup_printf("%s ", pre_text);
619 
620  status_print("%sClone Set: %s [%s]%s%s%s",
621  pre_text ? pre_text : "", rsc->id, ID(clone_data->xml_obj_child),
622  pcmk_is_set(rsc->flags, pcmk_rsc_promotable)? " (promotable)" : "",
623  pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
624  pcmk_is_set(rsc->flags, pcmk_rsc_managed)? "" : " (unmanaged)");
625 
626  if (options & pe_print_html) {
627  status_print("\n<ul>\n");
628 
629  } else if ((options & pe_print_log) == 0) {
630  status_print("\n");
631  }
632 
633  for (; gIter != NULL; gIter = gIter->next) {
634  gboolean print_full = FALSE;
635  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
636  gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
637 
638  if (options & pe_print_clone_details) {
639  print_full = TRUE;
640  }
641 
642  if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
643  // Print individual instance when unique (except stopped orphans)
644  if (partially_active
645  || !pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
646  print_full = TRUE;
647  }
648 
649  // Everything else in this block is for anonymous clones
650 
651  } else if (pcmk_is_set(options, pe_print_pending)
652  && (child_rsc->pending_task != NULL)
653  && strcmp(child_rsc->pending_task, "probe")) {
654  // Print individual instance when non-probe action is pending
655  print_full = TRUE;
656 
657  } else if (partially_active == FALSE) {
658  // List stopped instances when requested (except orphans)
659  if (!pcmk_is_set(child_rsc->flags, pcmk_rsc_removed)
660  && !pcmk_is_set(options, pe_print_clone_active)) {
661 
662  pcmk__add_word(&stopped_list, 1024, child_rsc->id);
663  }
664 
665  } else if (is_set_recursive(child_rsc, pcmk_rsc_removed, TRUE)
666  || !is_set_recursive(child_rsc, pcmk_rsc_managed, FALSE)
667  || is_set_recursive(child_rsc, pcmk_rsc_failed, TRUE)) {
668 
669  // Print individual instance when active orphaned/unmanaged/failed
670  print_full = TRUE;
671 
672  } else if (child_rsc->fns->active(child_rsc, TRUE)) {
673  // Instance of fully active anonymous clone
674 
675  pcmk_node_t *location = NULL;
676 
677  location = child_rsc->fns->location(child_rsc, NULL, TRUE);
678  if (location) {
679  // Instance is active on a single node
680 
681  enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
682 
683  if (location->details->online == FALSE && location->details->unclean) {
684  print_full = TRUE;
685 
686  } else if (a_role > pcmk_role_unpromoted) {
687  promoted_list = g_list_append(promoted_list, location);
688 
689  } else {
690  started_list = g_list_append(started_list, location);
691  }
692 
693  } else {
694  /* uncolocated group - bleh */
695  print_full = TRUE;
696  }
697 
698  } else {
699  // Instance of partially active anonymous clone
700  print_full = TRUE;
701  }
702 
703  if (print_full) {
704  if (options & pe_print_html) {
705  status_print("<li>\n");
706  }
707  child_rsc->fns->print(child_rsc, child_text, options, print_data);
708  if (options & pe_print_html) {
709  status_print("</li>\n");
710  }
711  }
712  }
713 
714  /* Promoted */
715  promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
716  for (gIter = promoted_list; gIter; gIter = gIter->next) {
717  pcmk_node_t *host = gIter->data;
718 
719  pcmk__add_word(&list_text, 1024, host->details->uname);
720  active_instances++;
721  }
722 
723  if (list_text != NULL) {
724  short_print((const char *) list_text->str, child_text,
725  PROMOTED_INSTANCES, NULL, options, print_data);
726  g_string_truncate(list_text, 0);
727  }
728  g_list_free(promoted_list);
729 
730  /* Started/Unpromoted */
731  started_list = g_list_sort(started_list, pe__cmp_node_name);
732  for (gIter = started_list; gIter; gIter = gIter->next) {
733  pcmk_node_t *host = gIter->data;
734 
735  pcmk__add_word(&list_text, 1024, host->details->uname);
736  active_instances++;
737  }
738 
739  if (list_text != NULL) {
741  enum rsc_role_e role = configured_role(rsc);
742 
743  if (role == pcmk_role_unpromoted) {
744  short_print((const char *) list_text->str, child_text,
745  UNPROMOTED_INSTANCES " (target-role)", NULL,
746  options, print_data);
747  } else {
748  short_print((const char *) list_text->str, child_text,
749  UNPROMOTED_INSTANCES, NULL, options, print_data);
750  }
751 
752  } else {
753  short_print((const char *) list_text->str, child_text, "Started",
754  NULL, options, print_data);
755  }
756  }
757 
758  g_list_free(started_list);
759 
760  if (!pcmk_is_set(options, pe_print_clone_active)) {
761  const char *state = "Stopped";
762  enum rsc_role_e role = configured_role(rsc);
763 
764  if (role == pcmk_role_stopped) {
765  state = "Stopped (disabled)";
766  }
767 
768  if (!pcmk_is_set(rsc->flags, pcmk_rsc_unique)
769  && (clone_data->clone_max > active_instances)) {
770 
771  GList *nIter;
772  GList *list = g_hash_table_get_values(rsc->allowed_nodes);
773 
774  /* Custom stopped list for non-unique clones */
775  if (stopped_list != NULL) {
776  g_string_truncate(stopped_list, 0);
777  }
778 
779  if (list == NULL) {
780  /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
781  * If we've not probed for them yet, the Stopped list will be empty
782  */
783  list = g_hash_table_get_values(rsc->known_on);
784  }
785 
786  list = g_list_sort(list, pe__cmp_node_name);
787  for (nIter = list; nIter != NULL; nIter = nIter->next) {
788  pcmk_node_t *node = (pcmk_node_t *) nIter->data;
789 
790  if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
791  pcmk__add_word(&stopped_list, 1024, node->details->uname);
792  }
793  }
794  g_list_free(list);
795  }
796 
797  if (stopped_list != NULL) {
798  short_print((const char *) stopped_list->str, child_text, state,
799  NULL, options, print_data);
800  }
801  }
802 
803  if (options & pe_print_html) {
804  status_print("</ul>\n");
805  }
806 
807  if (list_text != NULL) {
808  g_string_free(list_text, TRUE);
809  }
810 
811  if (stopped_list != NULL) {
812  g_string_free(stopped_list, TRUE);
813  }
814  free(child_text);
815 }
816 
817 PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
818  "GList *")
819 int
820 pe__clone_xml(pcmk__output_t *out, va_list args)
821 {
822  uint32_t show_opts = va_arg(args, uint32_t);
823  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
824  GList *only_node = va_arg(args, GList *);
825  GList *only_rsc = va_arg(args, GList *);
826 
827 
828  const char *desc = NULL;
829  GList *gIter = rsc->children;
830  GList *all = NULL;
831  int rc = pcmk_rc_no_output;
832  gboolean printed_header = FALSE;
833  gboolean print_everything = TRUE;
834 
835 
836 
837  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
838  return rc;
839  }
840 
841  print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
842  (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
843 
844  all = g_list_prepend(all, (gpointer) "*");
845 
846  for (; gIter != NULL; gIter = gIter->next) {
847  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
848 
849  if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
850  continue;
851  }
852 
853  if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
854  continue;
855  }
856 
857  if (!printed_header) {
858  printed_header = TRUE;
859 
860  desc = pe__resource_description(rsc, show_opts);
861  rc = pe__name_and_nvpairs_xml(out, true, "clone", 10,
862  "id", rsc->id,
863  "multi_state",
864  pe__rsc_bool_str(rsc, pcmk_rsc_promotable),
865  "unique", pe__rsc_bool_str(rsc, pcmk_rsc_unique),
866  "maintenance",
867  pe__rsc_bool_str(rsc, pcmk_rsc_maintenance),
868  "managed", pe__rsc_bool_str(rsc, pcmk_rsc_managed),
869  "disabled", pcmk__btoa(pe__resource_is_disabled(rsc)),
870  "failed", pe__rsc_bool_str(rsc, pcmk_rsc_failed),
871  "failure_ignored",
872  pe__rsc_bool_str(rsc, pcmk_rsc_ignore_failure),
873  "target_role", configured_role_str(rsc),
874  "description", desc);
875  CRM_ASSERT(rc == pcmk_rc_ok);
876  }
877 
878  out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
879  child_rsc, only_node, all);
880  }
881 
882  if (printed_header) {
884  }
885 
886  g_list_free(all);
887  return rc;
888 }
889 
890 PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
891  "GList *")
892 int
893 pe__clone_default(pcmk__output_t *out, va_list args)
894 {
895  uint32_t show_opts = va_arg(args, uint32_t);
896  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
897  GList *only_node = va_arg(args, GList *);
898  GList *only_rsc = va_arg(args, GList *);
899 
900  GHashTable *stopped = NULL;
901 
902  GString *list_text = NULL;
903 
904  GList *promoted_list = NULL;
905  GList *started_list = NULL;
906  GList *gIter = rsc->children;
907 
908  const char *desc = NULL;
909 
910  clone_variant_data_t *clone_data = NULL;
911  int active_instances = 0;
912  int rc = pcmk_rc_no_output;
913  gboolean print_everything = TRUE;
914 
915  desc = pe__resource_description(rsc, show_opts);
916 
917  get_clone_variant_data(clone_data, rsc);
918 
919  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
920  return rc;
921  }
922 
923  print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
924  (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
925 
926  for (; gIter != NULL; gIter = gIter->next) {
927  gboolean print_full = FALSE;
928  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
929  gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
930 
931  if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
932  continue;
933  }
934 
935  if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
936  continue;
937  }
938 
939  if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
940  print_full = TRUE;
941  }
942 
943  if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
944  // Print individual instance when unique (except stopped orphans)
945  if (partially_active
946  || !pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
947  print_full = TRUE;
948  }
949 
950  // Everything else in this block is for anonymous clones
951 
952  } else if (pcmk_is_set(show_opts, pcmk_show_pending)
953  && (child_rsc->pending_task != NULL)
954  && strcmp(child_rsc->pending_task, "probe")) {
955  // Print individual instance when non-probe action is pending
956  print_full = TRUE;
957 
958  } else if (partially_active == FALSE) {
959  // List stopped instances when requested (except orphans)
960  if (!pcmk_is_set(child_rsc->flags, pcmk_rsc_removed)
961  && !pcmk_is_set(show_opts, pcmk_show_clone_detail)
962  && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
963  if (stopped == NULL) {
964  stopped = pcmk__strkey_table(free, free);
965  }
966  g_hash_table_insert(stopped, strdup(child_rsc->id), strdup("Stopped"));
967  }
968 
969  } else if (is_set_recursive(child_rsc, pcmk_rsc_removed, TRUE)
970  || !is_set_recursive(child_rsc, pcmk_rsc_managed, FALSE)
971  || is_set_recursive(child_rsc, pcmk_rsc_failed, TRUE)) {
972 
973  // Print individual instance when active orphaned/unmanaged/failed
974  print_full = TRUE;
975 
976  } else if (child_rsc->fns->active(child_rsc, TRUE)) {
977  // Instance of fully active anonymous clone
978 
979  pcmk_node_t *location = NULL;
980 
981  location = child_rsc->fns->location(child_rsc, NULL, TRUE);
982  if (location) {
983  // Instance is active on a single node
984 
985  enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
986 
987  if (location->details->online == FALSE && location->details->unclean) {
988  print_full = TRUE;
989 
990  } else if (a_role > pcmk_role_unpromoted) {
991  promoted_list = g_list_append(promoted_list, location);
992 
993  } else {
994  started_list = g_list_append(started_list, location);
995  }
996 
997  } else {
998  /* uncolocated group - bleh */
999  print_full = TRUE;
1000  }
1001 
1002  } else {
1003  // Instance of partially active anonymous clone
1004  print_full = TRUE;
1005  }
1006 
1007  if (print_full) {
1008  GList *all = NULL;
1009 
1010  clone_header(out, &rc, rsc, clone_data, desc);
1011 
1012  /* Print every resource that's a child of this clone. */
1013  all = g_list_prepend(all, (gpointer) "*");
1014  out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
1015  child_rsc, only_node, all);
1016  g_list_free(all);
1017  }
1018  }
1019 
1020  if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
1021  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1022  return pcmk_rc_ok;
1023  }
1024 
1025  /* Promoted */
1026  promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
1027  for (gIter = promoted_list; gIter; gIter = gIter->next) {
1028  pcmk_node_t *host = gIter->data;
1029 
1030  if (!pcmk__str_in_list(host->details->uname, only_node,
1032  continue;
1033  }
1034 
1035  pcmk__add_word(&list_text, 1024, host->details->uname);
1036  active_instances++;
1037  }
1038  g_list_free(promoted_list);
1039 
1040  if ((list_text != NULL) && (list_text->len > 0)) {
1041  clone_header(out, &rc, rsc, clone_data, desc);
1042 
1043  out->list_item(out, NULL, PROMOTED_INSTANCES ": [ %s ]",
1044  (const char *) list_text->str);
1045  g_string_truncate(list_text, 0);
1046  }
1047 
1048  /* Started/Unpromoted */
1049  started_list = g_list_sort(started_list, pe__cmp_node_name);
1050  for (gIter = started_list; gIter; gIter = gIter->next) {
1051  pcmk_node_t *host = gIter->data;
1052 
1053  if (!pcmk__str_in_list(host->details->uname, only_node,
1055  continue;
1056  }
1057 
1058  pcmk__add_word(&list_text, 1024, host->details->uname);
1059  active_instances++;
1060  }
1061  g_list_free(started_list);
1062 
1063  if ((list_text != NULL) && (list_text->len > 0)) {
1064  clone_header(out, &rc, rsc, clone_data, desc);
1065 
1066  if (pcmk_is_set(rsc->flags, pcmk_rsc_promotable)) {
1067  enum rsc_role_e role = configured_role(rsc);
1068 
1069  if (role == pcmk_role_unpromoted) {
1070  out->list_item(out, NULL,
1071  UNPROMOTED_INSTANCES " (target-role): [ %s ]",
1072  (const char *) list_text->str);
1073  } else {
1074  out->list_item(out, NULL, UNPROMOTED_INSTANCES ": [ %s ]",
1075  (const char *) list_text->str);
1076  }
1077 
1078  } else {
1079  out->list_item(out, NULL, "Started: [ %s ]",
1080  (const char *) list_text->str);
1081  }
1082  }
1083 
1084  if (list_text != NULL) {
1085  g_string_free(list_text, TRUE);
1086  }
1087 
1088  if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1089  if (!pcmk_is_set(rsc->flags, pcmk_rsc_unique)
1090  && (clone_data->clone_max > active_instances)) {
1091 
1092  GList *nIter;
1093  GList *list = g_hash_table_get_values(rsc->allowed_nodes);
1094 
1095  /* Custom stopped table for non-unique clones */
1096  if (stopped != NULL) {
1097  g_hash_table_destroy(stopped);
1098  stopped = NULL;
1099  }
1100 
1101  if (list == NULL) {
1102  /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
1103  * If we've not probed for them yet, the Stopped list will be empty
1104  */
1105  list = g_hash_table_get_values(rsc->known_on);
1106  }
1107 
1108  list = g_list_sort(list, pe__cmp_node_name);
1109  for (nIter = list; nIter != NULL; nIter = nIter->next) {
1110  pcmk_node_t *node = (pcmk_node_t *) nIter->data;
1111 
1112  if (pe_find_node(rsc->running_on, node->details->uname) == NULL &&
1113  pcmk__str_in_list(node->details->uname, only_node,
1115  xmlNode *probe_op = pe__failed_probe_for_rsc(rsc, node->details->uname);
1116  const char *state = "Stopped";
1117 
1118  if (configured_role(rsc) == pcmk_role_stopped) {
1119  state = "Stopped (disabled)";
1120  }
1121 
1122  if (stopped == NULL) {
1123  stopped = pcmk__strkey_table(free, free);
1124  }
1125  if (probe_op != NULL) {
1126  int rc;
1127 
1129  g_hash_table_insert(stopped, strdup(node->details->uname),
1130  crm_strdup_printf("Stopped (%s)", services_ocf_exitcode_str(rc)));
1131  } else {
1132  g_hash_table_insert(stopped, strdup(node->details->uname),
1133  strdup(state));
1134  }
1135  }
1136  }
1137  g_list_free(list);
1138  }
1139 
1140  if (stopped != NULL) {
1141  GList *list = sorted_hash_table_values(stopped);
1142 
1143  clone_header(out, &rc, rsc, clone_data, desc);
1144 
1145  for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
1146  const char *status = status_iter->data;
1147  GList *nodes = nodes_with_status(stopped, status);
1148  GString *nodes_str = node_list_to_str(nodes);
1149 
1150  if (nodes_str != NULL) {
1151  if (nodes_str->len > 0) {
1152  out->list_item(out, NULL, "%s: [ %s ]", status,
1153  (const char *) nodes_str->str);
1154  }
1155  g_string_free(nodes_str, TRUE);
1156  }
1157 
1158  g_list_free(nodes);
1159  }
1160 
1161  g_list_free(list);
1162  g_hash_table_destroy(stopped);
1163 
1164  /* If there are no instances of this clone (perhaps because there are no
1165  * nodes configured), simply output the clone header by itself. This can
1166  * come up in PCS testing.
1167  */
1168  } else if (active_instances == 0) {
1169  clone_header(out, &rc, rsc, clone_data, desc);
1170  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1171  return rc;
1172  }
1173  }
1174 
1175  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1176  return rc;
1177 }
1178 
1179 void
1181 {
1182  clone_variant_data_t *clone_data = NULL;
1183 
1184  get_clone_variant_data(clone_data, rsc);
1185 
1186  pe_rsc_trace(rsc, "Freeing %s", rsc->id);
1187 
1188  for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1189  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
1190 
1191  CRM_ASSERT(child_rsc);
1192  pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
1193  free_xml(child_rsc->xml);
1194  child_rsc->xml = NULL;
1195  /* There could be a saved unexpanded xml */
1196  free_xml(child_rsc->orig_xml);
1197  child_rsc->orig_xml = NULL;
1198  child_rsc->fns->free(child_rsc);
1199  }
1200 
1201  g_list_free(rsc->children);
1202 
1203  if (clone_data) {
1204  CRM_ASSERT(clone_data->demote_notify == NULL);
1205  CRM_ASSERT(clone_data->stop_notify == NULL);
1206  CRM_ASSERT(clone_data->start_notify == NULL);
1207  CRM_ASSERT(clone_data->promote_notify == NULL);
1208  }
1209 
1210  common_free(rsc);
1211 }
1212 
1213 enum rsc_role_e
1214 clone_resource_state(const pcmk_resource_t * rsc, gboolean current)
1215 {
1216  enum rsc_role_e clone_role = pcmk_role_unknown;
1217  GList *gIter = rsc->children;
1218 
1219  for (; gIter != NULL; gIter = gIter->next) {
1220  pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
1221  enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
1222 
1223  if (a_role > clone_role) {
1224  clone_role = a_role;
1225  }
1226  }
1227 
1228  pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
1229  return clone_role;
1230 }
1231 
1239 bool
1241  const pcmk_scheduler_t *scheduler)
1242 {
1243  if (pe_rsc_is_clone(rsc)) {
1244  clone_variant_data_t *clone_data = rsc->variant_opaque;
1245 
1246  if (clone_data->clone_max == g_list_length(scheduler->nodes)) {
1247  return TRUE;
1248  }
1249  }
1250  return FALSE;
1251 }
1252 
1253 gboolean
1254 pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc,
1255  gboolean check_parent)
1256 {
1257  gboolean passes = FALSE;
1258  clone_variant_data_t *clone_data = NULL;
1259 
1261  passes = TRUE;
1262  } else {
1263  get_clone_variant_data(clone_data, rsc);
1264  passes = pcmk__str_in_list(ID(clone_data->xml_obj_child), only_rsc, pcmk__str_star_matches);
1265 
1266  if (!passes) {
1267  for (const GList *iter = rsc->children;
1268  iter != NULL; iter = iter->next) {
1269 
1270  const pcmk_resource_t *child_rsc = NULL;
1271 
1272  child_rsc = (const pcmk_resource_t *) iter->data;
1273  if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
1274  passes = TRUE;
1275  break;
1276  }
1277  }
1278  }
1279  }
1280  return !passes;
1281 }
1282 
1283 const char *
1285 {
1286  clone_variant_data_t *clone_data = NULL;
1287  get_clone_variant_data(clone_data, rsc);
1288  return ID(clone_data->xml_obj_child);
1289 }
1290 
1299 bool
1301 {
1302  clone_variant_data_t *clone_data = NULL;
1303 
1304  get_clone_variant_data(clone_data, clone);
1305  return pcmk_is_set(clone_data->flags, pcmk__clone_ordered);
1306 }
1307 
1318 int
1320 {
1321  clone_variant_data_t *clone_data = NULL;
1322 
1323  get_clone_variant_data(clone_data, clone);
1324  if (pcmk_is_set(clone_data->flags, flag)) {
1325  return pcmk_rc_already;
1326  }
1327  clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
1328  "Clone", clone->id,
1329  clone_data->flags, flag, "flag");
1330  return pcmk_rc_ok;
1331 }
1332 
1342 bool
1344 {
1345  clone_variant_data_t *clone_data = NULL;
1346 
1347  get_clone_variant_data(clone_data, clone);
1348  CRM_ASSERT(clone_data != NULL);
1349 
1350  return pcmk_all_flags_set(clone_data->flags, flags);
1351 }
1352 
1361 void
1363  bool any_demoting)
1364 {
1365  pcmk_action_t *action = NULL;
1366  pcmk_action_t *action_complete = NULL;
1367  clone_variant_data_t *clone_data = NULL;
1368 
1369  get_clone_variant_data(clone_data, clone);
1370 
1371  // Create a "promote" action for the clone itself
1373  !any_promoting, true);
1374 
1375  // Create a "promoted" action for when all promotions are done
1376  action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_PROMOTED,
1377  !any_promoting, true);
1378  action_complete->priority = INFINITY;
1379 
1380  // Create notification pseudo-actions for promotion
1381  if (clone_data->promote_notify == NULL) {
1382  clone_data->promote_notify = pe__action_notif_pseudo_ops(clone,
1384  action,
1385  action_complete);
1386  }
1387 
1388  // Create a "demote" action for the clone itself
1390  !any_demoting, true);
1391 
1392  // Create a "demoted" action for when all demotions are done
1393  action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_DEMOTED,
1394  !any_demoting, true);
1395  action_complete->priority = INFINITY;
1396 
1397  // Create notification pseudo-actions for demotion
1398  if (clone_data->demote_notify == NULL) {
1399  clone_data->demote_notify = pe__action_notif_pseudo_ops(clone,
1401  action,
1402  action_complete);
1403 
1404  if (clone_data->promote_notify != NULL) {
1405  order_actions(clone_data->stop_notify->post_done,
1406  clone_data->promote_notify->pre, pcmk__ar_ordered);
1407  order_actions(clone_data->start_notify->post_done,
1408  clone_data->promote_notify->pre, pcmk__ar_ordered);
1409  order_actions(clone_data->demote_notify->post_done,
1410  clone_data->promote_notify->pre, pcmk__ar_ordered);
1411  order_actions(clone_data->demote_notify->post_done,
1412  clone_data->start_notify->pre, pcmk__ar_ordered);
1413  order_actions(clone_data->demote_notify->post_done,
1414  clone_data->stop_notify->pre, pcmk__ar_ordered);
1415  }
1416  }
1417 }
1418 
1425 void
1427 {
1428  clone_variant_data_t *clone_data = NULL;
1429 
1430  get_clone_variant_data(clone_data, clone);
1431 
1432  pe__create_action_notifications(clone, clone_data->start_notify);
1433  pe__create_action_notifications(clone, clone_data->stop_notify);
1434  pe__create_action_notifications(clone, clone_data->promote_notify);
1435  pe__create_action_notifications(clone, clone_data->demote_notify);
1436 }
1437 
1444 void
1446 {
1447  clone_variant_data_t *clone_data = NULL;
1448 
1449  get_clone_variant_data(clone_data, clone);
1450 
1451  pe__free_action_notification_data(clone_data->demote_notify);
1452  clone_data->demote_notify = NULL;
1453 
1454  pe__free_action_notification_data(clone_data->stop_notify);
1455  clone_data->stop_notify = NULL;
1456 
1457  pe__free_action_notification_data(clone_data->start_notify);
1458  clone_data->start_notify = NULL;
1459 
1460  pe__free_action_notification_data(clone_data->promote_notify);
1461  clone_data->promote_notify = NULL;
1462 }
1463 
1474 void
1476  pcmk_action_t *start, pcmk_action_t *started,
1477  pcmk_action_t *stop, pcmk_action_t *stopped)
1478 {
1479  clone_variant_data_t *clone_data = NULL;
1480 
1481  get_clone_variant_data(clone_data, clone);
1482 
1483  if (clone_data->start_notify == NULL) {
1484  clone_data->start_notify = pe__action_notif_pseudo_ops(clone,
1486  start, started);
1487  }
1488 
1489  if (clone_data->stop_notify == NULL) {
1490  clone_data->stop_notify = pe__action_notif_pseudo_ops(clone,
1492  stop, stopped);
1493  if ((clone_data->start_notify != NULL)
1494  && (clone_data->stop_notify != NULL)) {
1495  order_actions(clone_data->stop_notify->post_done,
1496  clone_data->start_notify->pre, pcmk__ar_ordered);
1497  }
1498  }
1499 }
1500 
1509 unsigned int
1511 {
1512  const clone_variant_data_t *clone_data = NULL;
1513 
1514  get_clone_variant_data(clone_data, rsc);
1515  return clone_data->clone_node_max;
1516 }
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition: complex.c:962
bool pe__clone_is_ordered(const pcmk_resource_t *clone)
Definition: clone.c:1300
#define LOG_TRACE
Definition: logging.h:38
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:238
#define PCMK_XA_PROMOTED_MAX_LEGACY
Definition: msg_xml.h:56
xmlNode * orig_xml
Original resource configuration, if using template.
Definition: resources.h:407
GHashTable * known_on
Nodes where resource has been probed (key is node ID, not name)
Definition: resources.h:463
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
Definition: clone.c:1510
#define INFINITY
Definition: crm.h:98
#define PROMOTED_INSTANCES
Definition: clone.c:27
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
List nodes where a resource (or any of its children) is.
Definition: resources.h:339
Control output from tools.
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
int priority
Definition: actions.h:398
Stopped.
Definition: roles.h:29
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
Definition: clone.c:558
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition: utils.c:146
xmlNode * pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
Definition: utils.c:869
bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler)
Definition: clone.c:1240
void pe__create_clone_notifications(pcmk_resource_t *clone)
Definition: clone.c:1426
GList * children
Resource&#39;s child resources, if any.
Definition: resources.h:475
#define UNPROMOTED_INSTANCES
Definition: clone.c:28
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition: utils.c:450
void pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid, pcmk_scheduler_t *scheduler)
Definition: clone.c:210
xmlNode * xml
Resource configuration (possibly expanded from template)
Definition: resources.h:404
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Get resource&#39;s current or assigned role.
Definition: resources.h:327
pcmk_resource_t * pe__create_clone_child(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition: clone.c:245
#define XML_RSC_ATTR_INCARNATION
Definition: msg_xml.h:246
gboolean clone_active(pcmk_resource_t *rsc, gboolean all)
Definition: clone.c:442
Implementation of pcmk_action_t.
Definition: actions.h:390
#define pcmk__config_err(fmt...)
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
Definition: pe_output.c:22
GHashTable * meta
Resource&#39;s meta-attributes.
Definition: resources.h:471
Whether resource, its node, or entire cluster is in maintenance mode.
Definition: resources.h:181
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
int pe__clone_default(pcmk__output_t *out, va_list args)
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:700
#define XML_RSC_ATTR_STICKINESS
Definition: msg_xml.h:252
pcmk__clone_flags
enum crm_ais_msg_types type
Definition: cpg.c:48
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition: utils.c:546
void pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
Definition: utils.c:571
void(* print)(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: resources.h:306
void clone_free(pcmk_resource_t *rsc)
Definition: clone.c:1180
struct clone_variant_data_s clone_variant_data_t
gboolean clone_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition: clone.c:325
Implementation of pcmk_scheduler_t.
Definition: scheduler.h:172
char * pending_task
Pending action in history, if any.
Definition: resources.h:428
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
Definition: complex.c:603
const char * action
Definition: pcmk_fence.c:30
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
Definition: msg_xml.h:57
GList * nodes
Nodes in cluster.
Definition: scheduler.h:195
void clone_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: clone.c:593
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:789
const char * role2text(enum rsc_role_e role)
Definition: common.c:458
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1835
int pe__clone_promoted_max(const pcmk_resource_t *clone)
Definition: clone.c:97
#define pe_warn(fmt...)
Definition: internal.h:44
#define PCMK_ACTION_DEMOTE
Definition: actions.h:49
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition: status.c:391
void common_free(pcmk_resource_t *rsc)
Definition: complex.c:980
void(* free)(pcmk_resource_t *rsc)
Free all memory used by a resource.
Definition: resources.h:347
void pe__free_action_notification_data(notify_data_t *n_data)
Definition: pe_notif.c:960
Implementation of pcmk_resource_t.
Definition: resources.h:399
Actions are ordered (optionally, if no other flags are set)
#define XML_ATTR_ID
Definition: msg_xml.h:156
#define PCMK_META_CLONE_MAX
Definition: msg_xml.h:64
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:447
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:235
void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting)
Definition: clone.c:1362
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:597
Whether resource is considered failed.
Definition: resources.h:151
int pe__clone_xml(pcmk__output_t *out, va_list args)
pcmk_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
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition: pe_notif.c:943
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:99
struct pe_node_shared_s * details
Basic node information.
Definition: nodes.h:134
#define PCMK_ACTION_START
Definition: actions.h:71
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition: resources.h:429
const char * uname
Node name in cluster.
Definition: nodes.h:68
#define XML_RSC_ATTR_ORDERED
Definition: msg_xml.h:244
Unpromoted.
Definition: roles.h:31
rsc_role_e
Definition: roles.h:27
PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *", "GList *")
Definition: clone.c:817
#define PCMK_ACTION_STOP
Definition: actions.h:74
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:249
#define PCMK_META_PROMOTED_MAX
Definition: msg_xml.h:70
void free_xml(xmlNode *child)
Definition: xml.c:783
#define get_clone_variant_data(data, rsc)
Definition: clone.c:50
Implementation of pcmk_node_t.
Definition: nodes.h:130
enum rsc_role_e text2role(const char *role)
Definition: common.c:487
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:957
#define PCMK_META_PROMOTED_NODE_MAX
Definition: msg_xml.h:71
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:522
pcmk_resource_t * find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
Definition: clone.c:227
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, gboolean current)
Definition: clone.c:1214
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:250
void pe__free_clone_notification_data(pcmk_resource_t *clone)
Definition: clone.c:1445
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
Whether resource has an ignorable failure.
Definition: resources.h:175
notify_data_t * pe__action_notif_pseudo_ops(pcmk_resource_t *rsc, const char *task, pcmk_action_t *action, pcmk_action_t *complete)
Definition: pe_notif.c:435
void pe__create_clone_notif_pseudo_ops(pcmk_resource_t *clone, pcmk_action_t *start, pcmk_action_t *started, pcmk_action_t *stop, pcmk_action_t *stopped)
Definition: clone.c:1475
gboolean(* active)(pcmk_resource_t *rsc, gboolean all)
Check whether a resource is active.
Definition: resources.h:317
int pe__clone_node_max(const pcmk_resource_t *clone)
Definition: clone.c:80
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
Cluster status and scheduling.
int pe__clone_max(const pcmk_resource_t *clone)
Definition: clone.c:63
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:608
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:508
int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag)
Definition: clone.c:1319
pcmk_rsc_methods_t * fns
Resource object methods.
Definition: resources.h:416
void * variant_opaque
Variant-specific (and private) data.
Definition: resources.h:415
pcmk_scheduler_t * scheduler
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * pe__clone_child_id(const pcmk_resource_t *rsc)
Definition: clone.c:1284
#define status_print(fmt, args...)
bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
Definition: utils.c:775
This structure contains everything that makes up a single output formatter.
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
Definition: utils.c:725
#define PCMK_ACTION_PROMOTE
Definition: actions.h:65
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1023
gboolean(* is_filtered)(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Check whether a given resource is in a list of resources.
Definition: resources.h:369
GList * running_on
Nodes where resource may be active.
Definition: resources.h:460
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:317
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition: clone.c:1343
gboolean pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition: clone.c:1254
#define PCMK_ACTION_PROMOTED
Definition: actions.h:66
#define PCMK_META_CLONE_NODE_MAX
Definition: msg_xml.h:66
gboolean crm_is_true(const char *s)
Definition: strings.c:416
int pe__clone_promoted_node_max(const pcmk_resource_t *clone)
Definition: clone.c:114
Whether resource can be promoted and demoted.
Definition: resources.h:124
#define XML_CIB_TAG_GROUP
Definition: msg_xml.h:236
Resource role is unknown.
Definition: roles.h:28
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:37
#define ID(x)
Definition: msg_xml.h:474
#define PCMK_ACTION_DEMOTED
Definition: actions.h:50
Whether resource is managed.
Definition: resources.h:106
gboolean unclean
Whether node requires fencing.
Definition: nodes.h:76
Whether resource has been removed from the configuration.
Definition: resources.h:103
gboolean online
Whether online.
Definition: nodes.h:72
uint64_t flags
Definition: remote.c:215
Whether resource is not an anonymous clone instance.
Definition: resources.h:118
char * id
Resource ID in configuration.
Definition: resources.h:400
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition: resources.h:466
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:888