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