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