This source file includes following definitions.
- clone_header
- pe__force_anon
- find_clone_instance
- pe__create_clone_child
- clone_unpack
- clone_active
- short_print
- configured_role_str
- configured_role
- clone_print_xml
- is_set_recursive
- clone_print
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- clone_free
- clone_resource_state
- pe__is_universal_clone
- pe__clone_is_filtered
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/pengine/rules.h>
13 #include <crm/pengine/status.h>
14 #include <crm/pengine/internal.h>
15 #include <pe_status_private.h>
16 #include <crm/msg_xml.h>
17 #include <crm/common/output.h>
18 #include <crm/common/xml_internal.h>
19
20 #define VARIANT_CLONE 1
21 #include "./variant.h"
22
23 #ifdef PCMK__COMPAT_2_0
24 #define PROMOTED_INSTANCES RSC_ROLE_PROMOTED_LEGACY_S "s"
25 #define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_LEGACY_S "s"
26 #else
27 #define PROMOTED_INSTANCES RSC_ROLE_PROMOTED_S
28 #define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_S
29 #endif
30
31 static void
32 clone_header(pcmk__output_t *out, int *rc, pe_resource_t *rsc, clone_variant_data_t *clone_data)
33 {
34 char *attrs = NULL;
35 size_t len = 0;
36
37 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
38 pcmk__add_separated_word(&attrs, &len, "promotable", ", ");
39 }
40
41 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
42 pcmk__add_separated_word(&attrs, &len, "unique", ", ");
43 }
44
45 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
46 pcmk__add_separated_word(&attrs, &len, "unmanaged", ", ");
47 }
48
49 if (pe__resource_is_disabled(rsc)) {
50 pcmk__add_separated_word(&attrs, &len, "disabled", ", ");
51 }
52
53 if (attrs) {
54 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s] (%s)",
55 rsc->id, ID(clone_data->xml_obj_child),
56 attrs);
57 free(attrs);
58 } else {
59 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]",
60 rsc->id, ID(clone_data->xml_obj_child))
61 }
62 }
63
64 void
65 pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid,
66 pe_working_set_t *data_set)
67 {
68 if (pe_rsc_is_clone(rsc)) {
69 clone_variant_data_t *clone_data = NULL;
70
71 get_clone_variant_data(clone_data, rsc);
72
73 pe_warn("Ignoring " XML_RSC_ATTR_UNIQUE " for %s because %s resources "
74 "such as %s can be used only as anonymous clones",
75 rsc->id, standard, rid);
76
77 clone_data->clone_node_max = 1;
78 clone_data->clone_max = QB_MIN(clone_data->clone_max,
79 g_list_length(data_set->nodes));
80 }
81 }
82
83 pe_resource_t *
84 find_clone_instance(pe_resource_t * rsc, const char *sub_id, pe_working_set_t * data_set)
85 {
86 char *child_id = NULL;
87 pe_resource_t *child = NULL;
88 const char *child_base = NULL;
89 clone_variant_data_t *clone_data = NULL;
90
91 get_clone_variant_data(clone_data, rsc);
92
93 child_base = ID(clone_data->xml_obj_child);
94 child_id = crm_strdup_printf("%s:%s", child_base, sub_id);
95 child = pe_find_resource(rsc->children, child_id);
96
97 free(child_id);
98 return child;
99 }
100
101 pe_resource_t *
102 pe__create_clone_child(pe_resource_t *rsc, pe_working_set_t *data_set)
103 {
104 gboolean as_orphan = FALSE;
105 char *inc_num = NULL;
106 char *inc_max = NULL;
107 pe_resource_t *child_rsc = NULL;
108 xmlNode *child_copy = NULL;
109 clone_variant_data_t *clone_data = NULL;
110
111 get_clone_variant_data(clone_data, rsc);
112
113 CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
114
115 if (clone_data->total_clones >= clone_data->clone_max) {
116
117 as_orphan = TRUE;
118 }
119
120
121 inc_num = pcmk__itoa(clone_data->total_clones);
122 inc_max = pcmk__itoa(clone_data->clone_max);
123
124 child_copy = copy_xml(clone_data->xml_obj_child);
125
126 crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
127
128 if (common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) {
129 pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID));
130 child_rsc = NULL;
131 goto bail;
132 }
133
134
135 CRM_ASSERT(child_rsc);
136 clone_data->total_clones += 1;
137 pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
138 rsc->children = g_list_append(rsc->children, child_rsc);
139 if (as_orphan) {
140 pe__set_resource_flags_recursive(child_rsc, pe_rsc_orphan);
141 }
142
143 add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max);
144 pe_rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
145
146 bail:
147 free(inc_num);
148 free(inc_max);
149
150 return child_rsc;
151 }
152
153 gboolean
154 clone_unpack(pe_resource_t * rsc, pe_working_set_t * data_set)
155 {
156 int lpc = 0;
157 xmlNode *a_child = NULL;
158 xmlNode *xml_obj = rsc->xml;
159 clone_variant_data_t *clone_data = NULL;
160
161 const char *ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
162 const char *max_clones = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
163 const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
164
165 pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
166
167 clone_data = calloc(1, sizeof(clone_variant_data_t));
168 rsc->variant_opaque = clone_data;
169
170 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
171 const char *promoted_max = NULL;
172 const char *promoted_node_max = NULL;
173
174 promoted_max = g_hash_table_lookup(rsc->meta,
175 XML_RSC_ATTR_PROMOTED_MAX);
176 if (promoted_max == NULL) {
177
178 promoted_max = g_hash_table_lookup(rsc->meta,
179 PCMK_XE_PROMOTED_MAX_LEGACY);
180 }
181
182 promoted_node_max = g_hash_table_lookup(rsc->meta,
183 XML_RSC_ATTR_PROMOTED_NODEMAX);
184 if (promoted_node_max == NULL) {
185
186 promoted_node_max = g_hash_table_lookup(rsc->meta,
187 PCMK_XE_PROMOTED_NODE_MAX_LEGACY);
188 }
189
190
191 if (promoted_max == NULL) {
192 clone_data->promoted_max = 1;
193 } else {
194 pcmk__scan_min_int(promoted_max, &(clone_data->promoted_max), 0);
195 }
196
197
198 if (promoted_node_max == NULL) {
199 clone_data->promoted_node_max = 1;
200 } else {
201 pcmk__scan_min_int(promoted_node_max,
202 &(clone_data->promoted_node_max), 0);
203 }
204 }
205
206
207
208
209
210 if (max_clones_node == NULL) {
211 clone_data->clone_node_max = 1;
212 } else {
213 pcmk__scan_min_int(max_clones_node, &(clone_data->clone_node_max), 0);
214 }
215
216
217
218
219 if (max_clones == NULL) {
220 clone_data->clone_max = QB_MAX(1, g_list_length(data_set->nodes));
221 } else {
222 pcmk__scan_min_int(max_clones, &(clone_data->clone_max), 0);
223 }
224
225 clone_data->ordered = crm_is_true(ordered);
226
227 if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
228 pcmk__config_err("Ignoring " XML_RSC_ATTR_PROMOTED_MAX " for %s "
229 "because anonymous clones support only one instance "
230 "per node", rsc->id);
231 clone_data->clone_node_max = 1;
232 }
233
234 pe_rsc_trace(rsc, "Options for %s", rsc->id);
235 pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
236 pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
237 pe_rsc_trace(rsc, "\tClone is unique: %s",
238 pe__rsc_bool_str(rsc, pe_rsc_unique));
239 pe_rsc_trace(rsc, "\tClone is promotable: %s",
240 pe__rsc_bool_str(rsc, pe_rsc_promotable));
241
242
243 for (a_child = pcmk__xe_first_child(xml_obj); a_child != NULL;
244 a_child = pcmk__xe_next(a_child)) {
245
246 if (pcmk__str_any_of((const char *)a_child->name, XML_CIB_TAG_RESOURCE, XML_CIB_TAG_GROUP, NULL)) {
247 clone_data->xml_obj_child = a_child;
248 break;
249 }
250 }
251
252 if (clone_data->xml_obj_child == NULL) {
253 pcmk__config_err("%s has nothing to clone", rsc->id);
254 return FALSE;
255 }
256
257
258
259
260
261
262
263 if (g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
264 add_hash_param(rsc->meta, XML_RSC_ATTR_STICKINESS, "1");
265 }
266
267
268
269
270 add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE,
271 pe__rsc_bool_str(rsc, pe_rsc_unique));
272
273 if (clone_data->clone_max <= 0) {
274
275
276
277 if (pe__create_clone_child(rsc, data_set) == NULL) {
278 return FALSE;
279 }
280
281 } else {
282
283 for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
284 if (pe__create_clone_child(rsc, data_set) == NULL) {
285 return FALSE;
286 }
287 }
288 }
289
290 pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
291 return TRUE;
292 }
293
294 gboolean
295 clone_active(pe_resource_t * rsc, gboolean all)
296 {
297 GList *gIter = rsc->children;
298
299 for (; gIter != NULL; gIter = gIter->next) {
300 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
301 gboolean child_active = child_rsc->fns->active(child_rsc, all);
302
303 if (all == FALSE && child_active) {
304 return TRUE;
305 } else if (all && child_active == FALSE) {
306 return FALSE;
307 }
308 }
309
310 if (all) {
311 return TRUE;
312 } else {
313 return FALSE;
314 }
315 }
316
317 static void
318 short_print(char *list, const char *prefix, const char *type, const char *suffix, long options, void *print_data)
319 {
320 if(suffix == NULL) {
321 suffix = "";
322 }
323
324 if (list) {
325 if (options & pe_print_html) {
326 status_print("<li>");
327 }
328 status_print("%s%s: [ %s ]%s", prefix, type, list, suffix);
329
330 if (options & pe_print_html) {
331 status_print("</li>\n");
332
333 } else if (options & pe_print_suppres_nl) {
334
335 } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
336 status_print("\n");
337 }
338
339 }
340 }
341
342 static const char *
343 configured_role_str(pe_resource_t * rsc)
344 {
345 const char *target_role = g_hash_table_lookup(rsc->meta,
346 XML_RSC_ATTR_TARGET_ROLE);
347
348 if ((target_role == NULL) && rsc->children && rsc->children->data) {
349 target_role = g_hash_table_lookup(((pe_resource_t*)rsc->children->data)->meta,
350 XML_RSC_ATTR_TARGET_ROLE);
351 }
352 return target_role;
353 }
354
355 static enum rsc_role_e
356 configured_role(pe_resource_t * rsc)
357 {
358 const char *target_role = configured_role_str(rsc);
359
360 if (target_role) {
361 return text2role(target_role);
362 }
363 return RSC_ROLE_UNKNOWN;
364 }
365
366 static void
367 clone_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
368 {
369 char *child_text = crm_strdup_printf("%s ", pre_text);
370 const char *target_role = configured_role_str(rsc);
371 GList *gIter = rsc->children;
372
373 status_print("%s<clone ", pre_text);
374 status_print("id=\"%s\" ", rsc->id);
375 status_print("multi_state=\"%s\" ",
376 pe__rsc_bool_str(rsc, pe_rsc_promotable));
377 status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_unique));
378 status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
379 status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
380 status_print("failure_ignored=\"%s\" ",
381 pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
382 if (target_role) {
383 status_print("target_role=\"%s\" ", target_role);
384 }
385 status_print(">\n");
386
387 for (; gIter != NULL; gIter = gIter->next) {
388 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
389
390 child_rsc->fns->print(child_rsc, child_text, options, print_data);
391 }
392
393 status_print("%s</clone>\n", pre_text);
394 free(child_text);
395 }
396
397 bool is_set_recursive(pe_resource_t * rsc, long long flag, bool any)
398 {
399 GList *gIter;
400 bool all = !any;
401
402 if (pcmk_is_set(rsc->flags, flag)) {
403 if(any) {
404 return TRUE;
405 }
406 } else if(all) {
407 return FALSE;
408 }
409
410 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
411 if(is_set_recursive(gIter->data, flag, any)) {
412 if(any) {
413 return TRUE;
414 }
415
416 } else if(all) {
417 return FALSE;
418 }
419 }
420
421 if(all) {
422 return TRUE;
423 }
424 return FALSE;
425 }
426
427 void
428 clone_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
429 {
430 char *list_text = NULL;
431 char *child_text = NULL;
432 char *stopped_list = NULL;
433 size_t list_text_len = 0;
434 size_t stopped_list_len = 0;
435
436 GList *promoted_list = NULL;
437 GList *started_list = NULL;
438 GList *gIter = rsc->children;
439
440 clone_variant_data_t *clone_data = NULL;
441 int active_instances = 0;
442
443 if (pre_text == NULL) {
444 pre_text = " ";
445 }
446
447 if (options & pe_print_xml) {
448 clone_print_xml(rsc, pre_text, options, print_data);
449 return;
450 }
451
452 get_clone_variant_data(clone_data, rsc);
453
454 child_text = crm_strdup_printf("%s ", pre_text);
455
456 status_print("%sClone Set: %s [%s]%s%s%s",
457 pre_text ? pre_text : "", rsc->id, ID(clone_data->xml_obj_child),
458 pcmk_is_set(rsc->flags, pe_rsc_promotable)? " (promotable)" : "",
459 pcmk_is_set(rsc->flags, pe_rsc_unique)? " (unique)" : "",
460 pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : " (unmanaged)");
461
462 if (options & pe_print_html) {
463 status_print("\n<ul>\n");
464
465 } else if ((options & pe_print_log) == 0) {
466 status_print("\n");
467 }
468
469 for (; gIter != NULL; gIter = gIter->next) {
470 gboolean print_full = FALSE;
471 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
472 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
473
474 if (options & pe_print_clone_details) {
475 print_full = TRUE;
476 }
477
478 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
479
480 if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
481 print_full = TRUE;
482 }
483
484
485
486 } else if (pcmk_is_set(options, pe_print_pending)
487 && (child_rsc->pending_task != NULL)
488 && strcmp(child_rsc->pending_task, "probe")) {
489
490 print_full = TRUE;
491
492 } else if (partially_active == FALSE) {
493
494 if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
495 && !pcmk_is_set(options, pe_print_clone_active)) {
496 pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->id);
497 }
498
499 } else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
500 || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
501 || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
502
503
504 print_full = TRUE;
505
506 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
507
508
509 pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
510
511 if (location) {
512
513
514 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
515
516 if (location->details->online == FALSE && location->details->unclean) {
517 print_full = TRUE;
518
519 } else if (a_role > RSC_ROLE_UNPROMOTED) {
520 promoted_list = g_list_append(promoted_list, location);
521
522 } else {
523 started_list = g_list_append(started_list, location);
524 }
525
526 } else {
527
528 print_full = TRUE;
529 }
530
531 } else {
532
533 print_full = TRUE;
534 }
535
536 if (print_full) {
537 if (options & pe_print_html) {
538 status_print("<li>\n");
539 }
540 child_rsc->fns->print(child_rsc, child_text, options, print_data);
541 if (options & pe_print_html) {
542 status_print("</li>\n");
543 }
544 }
545 }
546
547
548 promoted_list = g_list_sort(promoted_list, sort_node_uname);
549 for (gIter = promoted_list; gIter; gIter = gIter->next) {
550 pe_node_t *host = gIter->data;
551
552 pcmk__add_word(&list_text, &list_text_len, host->details->uname);
553 active_instances++;
554 }
555
556 short_print(list_text, child_text, PROMOTED_INSTANCES, NULL, options,
557 print_data);
558 g_list_free(promoted_list);
559 free(list_text);
560 list_text = NULL;
561 list_text_len = 0;
562
563
564 started_list = g_list_sort(started_list, sort_node_uname);
565 for (gIter = started_list; gIter; gIter = gIter->next) {
566 pe_node_t *host = gIter->data;
567
568 pcmk__add_word(&list_text, &list_text_len, host->details->uname);
569 active_instances++;
570 }
571
572 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
573 enum rsc_role_e role = configured_role(rsc);
574
575 if (role == RSC_ROLE_UNPROMOTED) {
576 short_print(list_text, child_text,
577 UNPROMOTED_INSTANCES " (target-role)", NULL, options,
578 print_data);
579 } else {
580 short_print(list_text, child_text, UNPROMOTED_INSTANCES, NULL,
581 options, print_data);
582 }
583
584 } else {
585 short_print(list_text, child_text, "Started", NULL, options, print_data);
586 }
587
588 g_list_free(started_list);
589 free(list_text);
590 list_text = NULL;
591 list_text_len = 0;
592
593 if (!pcmk_is_set(options, pe_print_clone_active)) {
594 const char *state = "Stopped";
595 enum rsc_role_e role = configured_role(rsc);
596
597 if (role == RSC_ROLE_STOPPED) {
598 state = "Stopped (disabled)";
599 }
600
601 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
602 && (clone_data->clone_max > active_instances)) {
603
604 GList *nIter;
605 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
606
607
608 free(stopped_list);
609 stopped_list = NULL;
610 stopped_list_len = 0;
611
612 if (list == NULL) {
613
614
615
616 list = g_hash_table_get_values(rsc->known_on);
617 }
618
619 list = g_list_sort(list, sort_node_uname);
620 for (nIter = list; nIter != NULL; nIter = nIter->next) {
621 pe_node_t *node = (pe_node_t *)nIter->data;
622
623 if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
624 pcmk__add_word(&stopped_list, &stopped_list_len,
625 node->details->uname);
626 }
627 }
628 g_list_free(list);
629 }
630
631 short_print(stopped_list, child_text, state, NULL, options, print_data);
632 free(stopped_list);
633 }
634
635 if (options & pe_print_html) {
636 status_print("</ul>\n");
637 }
638
639 free(child_text);
640 }
641
642 PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GList *", "GList *")
643 int
644 pe__clone_xml(pcmk__output_t *out, va_list args)
645 {
646 unsigned int show_opts = va_arg(args, unsigned int);
647 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
648 GList *only_node = va_arg(args, GList *);
649 GList *only_rsc = va_arg(args, GList *);
650
651 GList *gIter = rsc->children;
652 GList *all = NULL;
653 int rc = pcmk_rc_no_output;
654 gboolean printed_header = FALSE;
655 gboolean print_everything = TRUE;
656
657 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
658 return rc;
659 }
660
661 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
662 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
663
664 all = g_list_prepend(all, (gpointer) "*");
665
666 for (; gIter != NULL; gIter = gIter->next) {
667 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
668
669 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
670 continue;
671 }
672
673 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
674 continue;
675 }
676
677 if (!printed_header) {
678 printed_header = TRUE;
679
680 rc = pe__name_and_nvpairs_xml(out, true, "clone", 8,
681 "id", rsc->id,
682 "multi_state", pe__rsc_bool_str(rsc, pe_rsc_promotable),
683 "unique", pe__rsc_bool_str(rsc, pe_rsc_unique),
684 "managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
685 "disabled", pcmk__btoa(pe__resource_is_disabled(rsc)),
686 "failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
687 "failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
688 "target_role", configured_role_str(rsc));
689 CRM_ASSERT(rc == pcmk_rc_ok);
690 }
691
692 out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
693 child_rsc, only_node, all);
694 }
695
696 if (printed_header) {
697 pcmk__output_xml_pop_parent(out);
698 }
699
700 g_list_free(all);
701 return rc;
702 }
703
704 PCMK__OUTPUT_ARGS("clone", "unsigned int", "pe_resource_t *", "GList *", "GList *")
705 int
706 pe__clone_default(pcmk__output_t *out, va_list args)
707 {
708 unsigned int show_opts = va_arg(args, unsigned int);
709 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
710 GList *only_node = va_arg(args, GList *);
711 GList *only_rsc = va_arg(args, GList *);
712
713 char *list_text = NULL;
714 char *stopped_list = NULL;
715 size_t list_text_len = 0;
716 size_t stopped_list_len = 0;
717
718 GList *promoted_list = NULL;
719 GList *started_list = NULL;
720 GList *gIter = rsc->children;
721
722 clone_variant_data_t *clone_data = NULL;
723 int active_instances = 0;
724 int rc = pcmk_rc_no_output;
725 gboolean print_everything = TRUE;
726
727 get_clone_variant_data(clone_data, rsc);
728
729 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
730 return rc;
731 }
732
733 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
734 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
735
736 for (; gIter != NULL; gIter = gIter->next) {
737 gboolean print_full = FALSE;
738 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
739 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
740
741 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
742 continue;
743 }
744
745 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
746 continue;
747 }
748
749 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
750 print_full = TRUE;
751 }
752
753 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
754
755 if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
756 print_full = TRUE;
757 }
758
759
760
761 } else if (pcmk_is_set(show_opts, pcmk_show_pending)
762 && (child_rsc->pending_task != NULL)
763 && strcmp(child_rsc->pending_task, "probe")) {
764
765 print_full = TRUE;
766
767 } else if (partially_active == FALSE) {
768
769 if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
770 && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
771 pcmk__add_word(&stopped_list, &stopped_list_len, child_rsc->id);
772 }
773
774 } else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
775 || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
776 || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
777
778
779 print_full = TRUE;
780
781 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
782
783
784 pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
785
786 if (location) {
787
788
789 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
790
791 if (location->details->online == FALSE && location->details->unclean) {
792 print_full = TRUE;
793
794 } else if (a_role > RSC_ROLE_UNPROMOTED) {
795 promoted_list = g_list_append(promoted_list, location);
796
797 } else {
798 started_list = g_list_append(started_list, location);
799 }
800
801 } else {
802
803 print_full = TRUE;
804 }
805
806 } else {
807
808 print_full = TRUE;
809 }
810
811 if (print_full) {
812 GList *all = NULL;
813
814 clone_header(out, &rc, rsc, clone_data);
815
816
817 all = g_list_prepend(all, (gpointer) "*");
818 out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
819 child_rsc, only_node, all);
820 g_list_free(all);
821 }
822 }
823
824 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
825 free(stopped_list);
826 PCMK__OUTPUT_LIST_FOOTER(out, rc);
827 return pcmk_rc_ok;
828 }
829
830
831 promoted_list = g_list_sort(promoted_list, sort_node_uname);
832 for (gIter = promoted_list; gIter; gIter = gIter->next) {
833 pe_node_t *host = gIter->data;
834
835 if (!pcmk__str_in_list(host->details->uname, only_node,
836 pcmk__str_star_matches|pcmk__str_casei)) {
837 continue;
838 }
839
840 pcmk__add_word(&list_text, &list_text_len, host->details->uname);
841 active_instances++;
842 }
843 g_list_free(promoted_list);
844
845 if (list_text != NULL) {
846 clone_header(out, &rc, rsc, clone_data);
847
848 out->list_item(out, NULL, PROMOTED_INSTANCES ": [ %s ]", list_text);
849 free(list_text);
850 list_text = NULL;
851 list_text_len = 0;
852 }
853
854
855 started_list = g_list_sort(started_list, sort_node_uname);
856 for (gIter = started_list; gIter; gIter = gIter->next) {
857 pe_node_t *host = gIter->data;
858
859 if (!pcmk__str_in_list(host->details->uname, only_node,
860 pcmk__str_star_matches|pcmk__str_casei)) {
861 continue;
862 }
863
864 pcmk__add_word(&list_text, &list_text_len, host->details->uname);
865 active_instances++;
866 }
867 g_list_free(started_list);
868
869 if (list_text != NULL) {
870 clone_header(out, &rc, rsc, clone_data);
871
872 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
873 enum rsc_role_e role = configured_role(rsc);
874
875 if (role == RSC_ROLE_UNPROMOTED) {
876 out->list_item(out, NULL,
877 UNPROMOTED_INSTANCES " (target-role): [ %s ]",
878 list_text);
879 } else {
880 out->list_item(out, NULL, UNPROMOTED_INSTANCES ": [ %s ]",
881 list_text);
882 }
883
884 } else {
885 out->list_item(out, NULL, "Started: [ %s ]", list_text);
886 }
887 free(list_text);
888 list_text = NULL;
889 list_text_len = 0;
890 }
891
892 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
893 const char *state = "Stopped";
894 enum rsc_role_e role = configured_role(rsc);
895
896 if (role == RSC_ROLE_STOPPED) {
897 state = "Stopped (disabled)";
898 }
899
900 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
901 && (clone_data->clone_max > active_instances)) {
902
903 GList *nIter;
904 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
905
906
907 free(stopped_list);
908 stopped_list = NULL;
909 stopped_list_len = 0;
910
911 if (list == NULL) {
912
913
914
915 list = g_hash_table_get_values(rsc->known_on);
916 }
917
918 list = g_list_sort(list, sort_node_uname);
919 for (nIter = list; nIter != NULL; nIter = nIter->next) {
920 pe_node_t *node = (pe_node_t *)nIter->data;
921
922 if (pe_find_node(rsc->running_on, node->details->uname) == NULL &&
923 pcmk__str_in_list(node->details->uname, only_node,
924 pcmk__str_star_matches|pcmk__str_casei)) {
925 pcmk__add_word(&stopped_list, &stopped_list_len,
926 node->details->uname);
927 }
928 }
929 g_list_free(list);
930 }
931
932 if (stopped_list != NULL) {
933 clone_header(out, &rc, rsc, clone_data);
934
935 out->list_item(out, NULL, "%s: [ %s ]", state, stopped_list);
936 free(stopped_list);
937 stopped_list_len = 0;
938
939
940
941
942
943 } else if (active_instances == 0) {
944 clone_header(out, &rc, rsc, clone_data);
945 PCMK__OUTPUT_LIST_FOOTER(out, rc);
946 return rc;
947 }
948 }
949
950 PCMK__OUTPUT_LIST_FOOTER(out, rc);
951 return rc;
952 }
953
954 void
955 clone_free(pe_resource_t * rsc)
956 {
957 clone_variant_data_t *clone_data = NULL;
958
959 get_clone_variant_data(clone_data, rsc);
960
961 pe_rsc_trace(rsc, "Freeing %s", rsc->id);
962
963 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
964 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
965
966 CRM_ASSERT(child_rsc);
967 pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
968 free_xml(child_rsc->xml);
969 child_rsc->xml = NULL;
970
971 free_xml(child_rsc->orig_xml);
972 child_rsc->orig_xml = NULL;
973 child_rsc->fns->free(child_rsc);
974 }
975
976 g_list_free(rsc->children);
977
978 if (clone_data) {
979 CRM_ASSERT(clone_data->demote_notify == NULL);
980 CRM_ASSERT(clone_data->stop_notify == NULL);
981 CRM_ASSERT(clone_data->start_notify == NULL);
982 CRM_ASSERT(clone_data->promote_notify == NULL);
983 }
984
985 common_free(rsc);
986 }
987
988 enum rsc_role_e
989 clone_resource_state(const pe_resource_t * rsc, gboolean current)
990 {
991 enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN;
992 GList *gIter = rsc->children;
993
994 for (; gIter != NULL; gIter = gIter->next) {
995 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
996 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
997
998 if (a_role > clone_role) {
999 clone_role = a_role;
1000 }
1001 }
1002
1003 pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
1004 return clone_role;
1005 }
1006
1007
1008
1009
1010
1011
1012
1013
1014 bool
1015 pe__is_universal_clone(pe_resource_t *rsc,
1016 pe_working_set_t *data_set)
1017 {
1018 if (pe_rsc_is_clone(rsc)) {
1019 clone_variant_data_t *clone_data = NULL;
1020
1021 get_clone_variant_data(clone_data, rsc);
1022 if (clone_data->clone_max == g_list_length(data_set->nodes)) {
1023 return TRUE;
1024 }
1025 }
1026 return FALSE;
1027 }
1028
1029 gboolean
1030 pe__clone_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
1031 {
1032 gboolean passes = FALSE;
1033 clone_variant_data_t *clone_data = NULL;
1034
1035 if (pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches)) {
1036 passes = TRUE;
1037 } else {
1038 get_clone_variant_data(clone_data, rsc);
1039 passes = pcmk__str_in_list(ID(clone_data->xml_obj_child), only_rsc, pcmk__str_star_matches);
1040
1041 if (!passes) {
1042 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1043 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1044
1045 if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
1046 passes = TRUE;
1047 break;
1048 }
1049 }
1050 }
1051 }
1052
1053 return !passes;
1054 }