This source file includes following definitions.
- mark_as_orphan
- force_non_unique_clone
- find_clone_instance
- create_child_clone
- master_unpack
- clone_unpack
- clone_active
- short_print
- configured_role_str
- configured_role
- clone_print_xml
- is_set_recursive
- clone_print
- clone_free
- clone_resource_state
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20
21 #include <crm/pengine/rules.h>
22 #include <crm/pengine/status.h>
23 #include <crm/pengine/internal.h>
24 #include <unpack.h>
25 #include <crm/msg_xml.h>
26
27 #define VARIANT_CLONE 1
28 #include "./variant.h"
29
30 void force_non_unique_clone(resource_t * rsc, const char *rid, pe_working_set_t * data_set);
31 resource_t *create_child_clone(resource_t * rsc, int sub_id, pe_working_set_t * data_set);
32
33 static void
34 mark_as_orphan(resource_t * rsc)
35 {
36 GListPtr gIter = rsc->children;
37
38 set_bit(rsc->flags, pe_rsc_orphan);
39
40 for (; gIter != NULL; gIter = gIter->next) {
41 resource_t *child = (resource_t *) gIter->data;
42
43 mark_as_orphan(child);
44 }
45 }
46
47 void
48 force_non_unique_clone(resource_t * rsc, const char *rid, pe_working_set_t * data_set)
49 {
50 if (pe_rsc_is_clone(rsc)) {
51 clone_variant_data_t *clone_data = NULL;
52
53 get_clone_variant_data(clone_data, rsc);
54
55 crm_config_warn("Clones %s contains non-OCF resource %s and so "
56 "can only be used as an anonymous clone. "
57 "Set the " XML_RSC_ATTR_UNIQUE " meta attribute to false", rsc->id, rid);
58
59 clone_data->clone_node_max = 1;
60 clone_data->clone_max = g_list_length(data_set->nodes);
61 clear_bit_recursive(rsc, pe_rsc_unique);
62 }
63 }
64
65 resource_t *
66 find_clone_instance(resource_t * rsc, const char *sub_id, pe_working_set_t * data_set)
67 {
68 char *child_id = NULL;
69 resource_t *child = NULL;
70 const char *child_base = NULL;
71 clone_variant_data_t *clone_data = NULL;
72
73 get_clone_variant_data(clone_data, rsc);
74
75 child_base = ID(clone_data->xml_obj_child);
76 child_id = crm_concat(child_base, sub_id, ':');
77 child = pe_find_resource(rsc->children, child_id);
78
79 free(child_id);
80 return child;
81 }
82
83 resource_t *
84 create_child_clone(resource_t * rsc, int sub_id, pe_working_set_t * data_set)
85 {
86 gboolean as_orphan = FALSE;
87 char *inc_num = NULL;
88 char *inc_max = NULL;
89 resource_t *child_rsc = NULL;
90 xmlNode *child_copy = NULL;
91 clone_variant_data_t *clone_data = NULL;
92
93 get_clone_variant_data(clone_data, rsc);
94
95 CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
96
97 if (sub_id < 0) {
98 as_orphan = TRUE;
99 sub_id = clone_data->total_clones;
100 }
101 inc_num = crm_itoa(sub_id);
102 inc_max = crm_itoa(clone_data->clone_max);
103
104 child_copy = copy_xml(clone_data->xml_obj_child);
105
106 crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
107
108 if (common_unpack(child_copy, &child_rsc, rsc, data_set) == FALSE) {
109 pe_err("Failed unpacking resource %s", crm_element_value(child_copy, XML_ATTR_ID));
110 child_rsc = NULL;
111 goto bail;
112 }
113
114
115 CRM_ASSERT(child_rsc);
116 clone_data->total_clones += 1;
117 pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
118 rsc->children = g_list_append(rsc->children, child_rsc);
119 if (as_orphan) {
120 mark_as_orphan(child_rsc);
121 }
122
123 add_hash_param(child_rsc->meta, XML_RSC_ATTR_INCARNATION_MAX, inc_max);
124
125 print_resource(LOG_DEBUG_3, "Added ", child_rsc, FALSE);
126
127 bail:
128 free(inc_num);
129 free(inc_max);
130
131 return child_rsc;
132 }
133
134 gboolean
135 master_unpack(resource_t * rsc, pe_working_set_t * data_set)
136 {
137 const char *master_max = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_MASTER_MAX);
138 const char *master_node_max = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_MASTER_NODEMAX);
139
140 g_hash_table_replace(rsc->meta, strdup("stateful"), strdup(XML_BOOLEAN_TRUE));
141 if (clone_unpack(rsc, data_set)) {
142 clone_variant_data_t *clone_data = NULL;
143
144 get_clone_variant_data(clone_data, rsc);
145 clone_data->master_max = crm_parse_int(master_max, "1");
146 clone_data->master_node_max = crm_parse_int(master_node_max, "1");
147 return TRUE;
148 }
149 return FALSE;
150 }
151
152 gboolean
153 clone_unpack(resource_t * rsc, pe_working_set_t * data_set)
154 {
155 int lpc = 0;
156 xmlNode *a_child = NULL;
157 xmlNode *xml_obj = rsc->xml;
158 clone_variant_data_t *clone_data = NULL;
159
160 const char *ordered = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED);
161 const char *interleave = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERLEAVE);
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 clone_data->active_clones = 0;
171 clone_data->xml_obj_child = NULL;
172 clone_data->clone_node_max = crm_parse_int(max_clones_node, "1");
173
174 if (max_clones) {
175 clone_data->clone_max = crm_parse_int(max_clones, "1");
176
177 } else if (g_list_length(data_set->nodes) > 0) {
178 clone_data->clone_max = g_list_length(data_set->nodes);
179
180 } else {
181 clone_data->clone_max = 1;
182 }
183
184 clone_data->interleave = crm_is_true(interleave);
185 clone_data->ordered = crm_is_true(ordered);
186
187 if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
188 crm_config_err("Anonymous clones (%s) may only support one copy per node", rsc->id);
189 clone_data->clone_node_max = 1;
190 }
191
192 pe_rsc_trace(rsc, "Options for %s", rsc->id);
193 pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
194 pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
195 pe_rsc_trace(rsc, "\tClone is unique: %s",
196 is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
197
198
199 for (a_child = __xml_first_child(xml_obj); a_child != NULL;
200 a_child = __xml_next_element(a_child)) {
201
202 if (crm_str_eq((const char *)a_child->name, XML_CIB_TAG_RESOURCE, TRUE)
203 || crm_str_eq((const char *)a_child->name, XML_CIB_TAG_GROUP, TRUE)) {
204 clone_data->xml_obj_child = a_child;
205 break;
206 }
207 }
208
209 if (clone_data->xml_obj_child == NULL) {
210 crm_config_err("%s has nothing to clone", rsc->id);
211 return FALSE;
212 }
213
214
215
216
217
218
219
220 if (g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
221 add_hash_param(rsc->meta, XML_RSC_ATTR_STICKINESS, "1");
222 }
223
224 pe_rsc_trace(rsc, "\tClone is unique (fixed): %s",
225 is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
226 clone_data->notify_confirm = is_set(rsc->flags, pe_rsc_notify);
227 add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE,
228 is_set(rsc->flags, pe_rsc_unique) ? XML_BOOLEAN_TRUE : XML_BOOLEAN_FALSE);
229
230 for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
231 if (create_child_clone(rsc, lpc, data_set) == NULL) {
232 return FALSE;
233 }
234 }
235
236 if (clone_data->clone_max == 0) {
237
238
239
240 if (create_child_clone(rsc, -1, data_set) == NULL) {
241 return FALSE;
242 }
243 }
244
245 pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
246 return TRUE;
247 }
248
249 gboolean
250 clone_active(resource_t * rsc, gboolean all)
251 {
252 GListPtr gIter = rsc->children;
253
254 for (; gIter != NULL; gIter = gIter->next) {
255 resource_t *child_rsc = (resource_t *) gIter->data;
256 gboolean child_active = child_rsc->fns->active(child_rsc, all);
257
258 if (all == FALSE && child_active) {
259 return TRUE;
260 } else if (all && child_active == FALSE) {
261 return FALSE;
262 }
263 }
264
265 if (all) {
266 return TRUE;
267 } else {
268 return FALSE;
269 }
270 }
271
272 static void
273 short_print(char *list, const char *prefix, const char *type, const char *suffix, long options, void *print_data)
274 {
275 if(suffix == NULL) {
276 suffix = "";
277 }
278
279 if (list) {
280 if (options & pe_print_html) {
281 status_print("<li>");
282 }
283 status_print("%s%s: [%s ]%s", prefix, type, list, suffix);
284
285 if (options & pe_print_html) {
286 status_print("</li>\n");
287
288 } else if (options & pe_print_suppres_nl) {
289
290 } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
291 status_print("\n");
292 }
293
294 }
295 }
296
297 static const char *
298 configured_role_str(resource_t * rsc)
299 {
300 const char *target_role = g_hash_table_lookup(rsc->meta,
301 XML_RSC_ATTR_TARGET_ROLE);
302
303 if ((target_role == NULL) && rsc->children && rsc->children->data) {
304 target_role = g_hash_table_lookup(((resource_t*)rsc->children->data)->meta,
305 XML_RSC_ATTR_TARGET_ROLE);
306 }
307 return target_role;
308 }
309
310 static enum rsc_role_e
311 configured_role(resource_t * rsc)
312 {
313 const char *target_role = configured_role_str(rsc);
314
315 if (target_role) {
316 return text2role(target_role);
317 }
318 return RSC_ROLE_UNKNOWN;
319 }
320
321 static void
322 clone_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data)
323 {
324 int is_master_slave = rsc->variant == pe_master ? 1 : 0;
325 char *child_text = crm_concat(pre_text, " ", ' ');
326 const char *target_role = configured_role_str(rsc);
327 GListPtr gIter = rsc->children;
328
329 status_print("%s<clone ", pre_text);
330 status_print("id=\"%s\" ", rsc->id);
331 status_print("multi_state=\"%s\" ", is_master_slave ? "true" : "false");
332 status_print("unique=\"%s\" ", is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
333 status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false");
334 status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false");
335 status_print("failure_ignored=\"%s\" ",
336 is_set(rsc->flags, pe_rsc_failure_ignored) ? "true" : "false");
337 if (target_role) {
338 status_print("target_role=\"%s\" ", target_role);
339 }
340 status_print(">\n");
341
342 for (; gIter != NULL; gIter = gIter->next) {
343 resource_t *child_rsc = (resource_t *) gIter->data;
344
345 child_rsc->fns->print(child_rsc, child_text, options, print_data);
346 }
347
348 status_print("%s</clone>\n", pre_text);
349 free(child_text);
350 }
351
352 bool is_set_recursive(resource_t * rsc, long long flag, bool any)
353 {
354 GListPtr gIter;
355 bool all = !any;
356
357 if(is_set(rsc->flags, flag)) {
358 if(any) {
359 return TRUE;
360 }
361 } else if(all) {
362 return FALSE;
363 }
364
365 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
366 if(is_set_recursive(gIter->data, flag, any)) {
367 if(any) {
368 return TRUE;
369 }
370
371 } else if(all) {
372 return FALSE;
373 }
374 }
375
376 if(all) {
377 return TRUE;
378 }
379 return FALSE;
380 }
381
382 void
383 clone_print(resource_t * rsc, const char *pre_text, long options, void *print_data)
384 {
385 char *list_text = NULL;
386 char *child_text = NULL;
387 char *stopped_list = NULL;
388 const char *type = "Clone";
389
390 GListPtr master_list = NULL;
391 GListPtr started_list = NULL;
392 GListPtr gIter = rsc->children;
393
394 clone_variant_data_t *clone_data = NULL;
395 int active_instances = 0;
396
397 if (pre_text == NULL) {
398 pre_text = " ";
399 }
400
401 if (options & pe_print_xml) {
402 clone_print_xml(rsc, pre_text, options, print_data);
403 return;
404 }
405
406 get_clone_variant_data(clone_data, rsc);
407
408 child_text = crm_concat(pre_text, " ", ' ');
409
410 if (rsc->variant == pe_master) {
411 type = "Master/Slave";
412 }
413
414 status_print("%s%s Set: %s [%s]%s%s",
415 pre_text ? pre_text : "", type, rsc->id, ID(clone_data->xml_obj_child),
416 is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
417 is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
418
419 if (options & pe_print_html) {
420 status_print("\n<ul>\n");
421
422 } else if ((options & pe_print_log) == 0) {
423 status_print("\n");
424 }
425
426 for (; gIter != NULL; gIter = gIter->next) {
427 gboolean print_full = FALSE;
428 resource_t *child_rsc = (resource_t *) gIter->data;
429
430 if (options & pe_print_clone_details) {
431 print_full = TRUE;
432 }
433
434 if (child_rsc->fns->active(child_rsc, FALSE) == FALSE) {
435
436 if (is_set(child_rsc->flags, pe_rsc_orphan)) {
437 continue;
438
439 } else if (is_set(rsc->flags, pe_rsc_unique)) {
440 print_full = TRUE;
441
442 } else if (is_not_set(options, pe_print_clone_active)) {
443 stopped_list = add_list_element(stopped_list, child_rsc->id);
444 }
445
446 } else if (is_set_recursive(child_rsc, pe_rsc_unique, TRUE)
447 || is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
448 || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
449 || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
450
451
452 print_full = TRUE;
453
454 } else if (is_set(options, pe_print_pending) && child_rsc->pending_task != NULL) {
455
456 print_full = TRUE;
457
458 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
459
460 node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
461
462 if (location) {
463 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
464
465 if (location->details->online == FALSE && location->details->unclean) {
466 print_full = TRUE;
467
468 } else if (a_role > RSC_ROLE_SLAVE) {
469
470 master_list = g_list_append(master_list, location);
471
472 } else {
473
474 started_list = g_list_append(started_list, location);
475 }
476
477 } else {
478
479 print_full = TRUE;
480 }
481
482 } else {
483
484 print_full = TRUE;
485 }
486
487 if (print_full) {
488 if (options & pe_print_html) {
489 status_print("<li>\n");
490 }
491 child_rsc->fns->print(child_rsc, child_text, options, print_data);
492 if (options & pe_print_html) {
493 status_print("</li>\n");
494 }
495 }
496 }
497
498
499 master_list = g_list_sort(master_list, sort_node_uname);
500 for (gIter = master_list; gIter; gIter = gIter->next) {
501 node_t *host = gIter->data;
502
503 list_text = add_list_element(list_text, host->details->uname);
504 active_instances++;
505 }
506
507 short_print(list_text, child_text, "Masters", NULL, options, print_data);
508 g_list_free(master_list);
509 free(list_text);
510 list_text = NULL;
511
512
513 started_list = g_list_sort(started_list, sort_node_uname);
514 for (gIter = started_list; gIter; gIter = gIter->next) {
515 node_t *host = gIter->data;
516
517 list_text = add_list_element(list_text, host->details->uname);
518 active_instances++;
519 }
520
521 if(rsc->variant == pe_master) {
522 enum rsc_role_e role = configured_role(rsc);
523
524 if(role == RSC_ROLE_SLAVE) {
525 short_print(list_text, child_text, "Slaves (target-role)", NULL, options, print_data);
526 } else {
527 short_print(list_text, child_text, "Slaves", NULL, options, print_data);
528 }
529
530 } else {
531 short_print(list_text, child_text, "Started", NULL, options, print_data);
532 }
533
534 g_list_free(started_list);
535 free(list_text);
536 list_text = NULL;
537
538 if (is_not_set(options, pe_print_clone_active)) {
539 const char *state = "Stopped";
540 enum rsc_role_e role = configured_role(rsc);
541
542 if (role == RSC_ROLE_STOPPED) {
543 state = "Stopped (disabled)";
544 }
545
546 if (is_not_set(rsc->flags, pe_rsc_unique)
547 && (clone_data->clone_max > active_instances)) {
548
549 GListPtr nIter;
550 GListPtr list = g_hash_table_get_values(rsc->allowed_nodes);
551
552
553 free(stopped_list); stopped_list = NULL;
554
555 if (g_list_length(list) == 0) {
556
557
558
559 list = g_hash_table_get_values(rsc->known_on);
560 }
561
562 list = g_list_sort(list, sort_node_uname);
563 for (nIter = list; nIter != NULL; nIter = nIter->next) {
564 node_t *node = (node_t *)nIter->data;
565
566 if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
567 stopped_list = add_list_element(stopped_list, node->details->uname);
568 }
569 }
570 g_list_free(list);
571 }
572
573 short_print(stopped_list, child_text, state, NULL, options, print_data);
574 free(stopped_list);
575 }
576
577 if (options & pe_print_html) {
578 status_print("</ul>\n");
579 }
580
581 free(child_text);
582 }
583
584 void
585 clone_free(resource_t * rsc)
586 {
587 GListPtr gIter = rsc->children;
588 clone_variant_data_t *clone_data = NULL;
589
590 get_clone_variant_data(clone_data, rsc);
591
592 pe_rsc_trace(rsc, "Freeing %s", rsc->id);
593
594 for (; gIter != NULL; gIter = gIter->next) {
595 resource_t *child_rsc = (resource_t *) gIter->data;
596
597 CRM_ASSERT(child_rsc);
598 pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
599 free_xml(child_rsc->xml);
600 child_rsc->xml = NULL;
601
602 free_xml(child_rsc->orig_xml);
603 child_rsc->orig_xml = NULL;
604 child_rsc->fns->free(child_rsc);
605 }
606
607 g_list_free(rsc->children);
608
609 if (clone_data) {
610 CRM_ASSERT(clone_data->demote_notify == NULL);
611 CRM_ASSERT(clone_data->stop_notify == NULL);
612 CRM_ASSERT(clone_data->start_notify == NULL);
613 CRM_ASSERT(clone_data->promote_notify == NULL);
614 }
615
616 common_free(rsc);
617 }
618
619 enum rsc_role_e
620 clone_resource_state(const resource_t * rsc, gboolean current)
621 {
622 enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN;
623 GListPtr gIter = rsc->children;
624
625 for (; gIter != NULL; gIter = gIter->next) {
626 resource_t *child_rsc = (resource_t *) gIter->data;
627 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
628
629 if (a_role > clone_role) {
630 clone_role = a_role;
631 }
632 }
633
634 pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
635 return clone_role;
636 }