This source file includes following definitions.
- get_resource_type
- dup_attr
- expand_parents_fixed_nvpairs
- get_meta_attributes
- get_rsc_attributes
- template_op_key
- unpack_template
- add_template_rsc
- detect_unique
- free_params_table
- pe_rsc_params
- unpack_requires
- unpack_priority
- unpack_stickiness
- unpack_migration_threshold
- pe__unpack_resource
- is_parent
- uber_parent
- pe__const_top_resource
- common_free
- pe__count_active_node
- active_node
- pe__find_active_requires
- pe__count_common
- pe__set_next_role
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <libxml/tree.h>
13
14 #include <crm/pengine/internal.h>
15 #include <crm/common/xml.h>
16 #include <crm/common/xml_internal.h>
17 #include <crm/common/scheduler_internal.h>
18
19 #include "pe_status_private.h"
20
21 void populate_hash(xmlNode * nvpair_list, GHashTable * hash, const char **attrs, int attrs_length);
22
23 static pcmk_node_t *active_node(const pcmk_resource_t *rsc,
24 unsigned int *count_all,
25 unsigned int *count_clean);
26
27 static pcmk__rsc_methods_t resource_class_functions[] = {
28 {
29 native_unpack,
30 native_find_rsc,
31 native_active,
32 native_resource_state,
33 native_location,
34 native_free,
35 pe__count_common,
36 pe__native_is_filtered,
37 active_node,
38 pe__primitive_max_per_node,
39 },
40 {
41 group_unpack,
42 native_find_rsc,
43 group_active,
44 group_resource_state,
45 native_location,
46 group_free,
47 pe__count_common,
48 pe__group_is_filtered,
49 active_node,
50 pe__group_max_per_node,
51 },
52 {
53 clone_unpack,
54 native_find_rsc,
55 clone_active,
56 clone_resource_state,
57 native_location,
58 clone_free,
59 pe__count_common,
60 pe__clone_is_filtered,
61 active_node,
62 pe__clone_max_per_node,
63 },
64 {
65 pe__unpack_bundle,
66 native_find_rsc,
67 pe__bundle_active,
68 pe__bundle_resource_state,
69 native_location,
70 pe__free_bundle,
71 pe__count_bundle,
72 pe__bundle_is_filtered,
73 pe__bundle_active_node,
74 pe__bundle_max_per_node,
75 }
76 };
77
78 static enum pcmk__rsc_variant
79 get_resource_type(const char *name)
80 {
81 if (pcmk__str_eq(name, PCMK_XE_PRIMITIVE, pcmk__str_casei)) {
82 return pcmk__rsc_variant_primitive;
83
84 } else if (pcmk__str_eq(name, PCMK_XE_GROUP, pcmk__str_casei)) {
85 return pcmk__rsc_variant_group;
86
87 } else if (pcmk__str_eq(name, PCMK_XE_CLONE, pcmk__str_casei)) {
88 return pcmk__rsc_variant_clone;
89
90 } else if (pcmk__str_eq(name, PCMK_XE_BUNDLE, pcmk__str_casei)) {
91 return pcmk__rsc_variant_bundle;
92 }
93
94 return pcmk__rsc_variant_unknown;
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108 static void
109 dup_attr(gpointer key, gpointer value, gpointer user_data)
110 {
111 GHashTable *table = user_data;
112
113 CRM_CHECK((key != NULL) && (table != NULL), return);
114 if (pcmk__str_eq((const char *) value, "#default", pcmk__str_casei)) {
115
116 pcmk__config_warn("Support for setting meta-attributes (such as %s) to "
117 "the explicit value '#default' is deprecated and "
118 "will be removed in a future release",
119 (const char *) key);
120 } else if ((value != NULL) && (g_hash_table_lookup(table, key) == NULL)) {
121 pcmk__insert_dup(table, (const char *) key, (const char *) value);
122 }
123 }
124
125 static void
126 expand_parents_fixed_nvpairs(pcmk_resource_t *rsc,
127 const pcmk_rule_input_t *rule_input,
128 GHashTable *meta_hash, pcmk_scheduler_t *scheduler)
129 {
130 GHashTable *parent_orig_meta = pcmk__strkey_table(free, free);
131 pcmk_resource_t *p = rsc->priv->parent;
132
133 if (p == NULL) {
134 return ;
135 }
136
137
138
139
140
141
142 while(p != NULL) {
143
144 pe__unpack_dataset_nvpairs(p->priv->xml, PCMK_XE_META_ATTRIBUTES,
145 rule_input, parent_orig_meta, NULL,
146 scheduler);
147 p = p->priv->parent;
148 }
149
150 if (parent_orig_meta != NULL) {
151
152 g_hash_table_foreach(parent_orig_meta, dup_attr, meta_hash);
153 }
154
155 if (parent_orig_meta != NULL) {
156 g_hash_table_destroy(parent_orig_meta);
157 }
158
159 return ;
160
161 }
162
163
164
165
166
167
168
169
170
171 void
172 get_meta_attributes(GHashTable * meta_hash, pcmk_resource_t * rsc,
173 pcmk_node_t *node, pcmk_scheduler_t *scheduler)
174 {
175 const pcmk_rule_input_t rule_input = {
176 .now = scheduler->priv->now,
177 .rsc_standard = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS),
178 .rsc_provider = crm_element_value(rsc->priv->xml, PCMK_XA_PROVIDER),
179 .rsc_agent = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE)
180 };
181
182 for (xmlAttrPtr a = pcmk__xe_first_attr(rsc->priv->xml);
183 a != NULL; a = a->next) {
184
185 if (a->children != NULL) {
186 dup_attr((gpointer) a->name, (gpointer) a->children->content,
187 meta_hash);
188 }
189 }
190
191 pe__unpack_dataset_nvpairs(rsc->priv->xml, PCMK_XE_META_ATTRIBUTES,
192 &rule_input, meta_hash, NULL, scheduler);
193
194
195
196
197
198 if (rsc->priv->parent != NULL) {
199 expand_parents_fixed_nvpairs(rsc, &rule_input, meta_hash, scheduler);
200 }
201
202
203 pe__unpack_dataset_nvpairs(scheduler->priv->rsc_defaults,
204 PCMK_XE_META_ATTRIBUTES, &rule_input, meta_hash,
205 NULL, scheduler);
206
207
208
209
210
211 if (rsc->priv->parent != NULL) {
212 g_hash_table_foreach(rsc->priv->parent->priv->meta, dup_attr,
213 meta_hash);
214 }
215 }
216
217
218
219
220
221
222
223
224
225 void
226 get_rsc_attributes(GHashTable *instance_attrs, const pcmk_resource_t *rsc,
227 const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
228 {
229 pcmk_rule_input_t rule_input = {
230 .now = NULL,
231 };
232
233 CRM_CHECK((instance_attrs != NULL) && (rsc != NULL) && (scheduler != NULL),
234 return);
235
236 rule_input.now = scheduler->priv->now;
237 if (node != NULL) {
238 rule_input.node_attrs = node->priv->attrs;
239 }
240
241
242 pe__unpack_dataset_nvpairs(rsc->priv->xml, PCMK_XE_INSTANCE_ATTRIBUTES,
243 &rule_input, instance_attrs, NULL, scheduler);
244 if (rsc->priv->parent != NULL) {
245 get_rsc_attributes(instance_attrs, rsc->priv->parent, node, scheduler);
246 }
247 }
248
249 static char *
250 template_op_key(xmlNode * op)
251 {
252 const char *name = crm_element_value(op, PCMK_XA_NAME);
253 const char *role = crm_element_value(op, PCMK_XA_ROLE);
254 char *key = NULL;
255
256 if ((role == NULL)
257 || pcmk__strcase_any_of(role, PCMK_ROLE_STARTED, PCMK_ROLE_UNPROMOTED,
258 PCMK__ROLE_UNPROMOTED_LEGACY, NULL)) {
259 role = PCMK__ROLE_UNKNOWN;
260 }
261
262 key = crm_strdup_printf("%s-%s", name, role);
263 return key;
264 }
265
266 static gboolean
267 unpack_template(xmlNode *xml_obj, xmlNode **expanded_xml,
268 pcmk_scheduler_t *scheduler)
269 {
270 xmlNode *cib_resources = NULL;
271 xmlNode *template = NULL;
272 xmlNode *new_xml = NULL;
273 xmlNode *child_xml = NULL;
274 xmlNode *rsc_ops = NULL;
275 xmlNode *template_ops = NULL;
276 const char *template_ref = NULL;
277 const char *id = NULL;
278
279 if (xml_obj == NULL) {
280 pcmk__config_err("No resource object for template unpacking");
281 return FALSE;
282 }
283
284 template_ref = crm_element_value(xml_obj, PCMK_XA_TEMPLATE);
285 if (template_ref == NULL) {
286 return TRUE;
287 }
288
289 id = pcmk__xe_id(xml_obj);
290 if (id == NULL) {
291 pcmk__config_err("'%s' object must have a id", xml_obj->name);
292 return FALSE;
293 }
294
295 if (pcmk__str_eq(template_ref, id, pcmk__str_none)) {
296 pcmk__config_err("The resource object '%s' should not reference itself",
297 id);
298 return FALSE;
299 }
300
301 cib_resources = pcmk__xpath_find_one(scheduler->input->doc,
302 "//" PCMK_XE_RESOURCES, LOG_TRACE);
303 if (cib_resources == NULL) {
304 pcmk__config_err("No resources configured");
305 return FALSE;
306 }
307
308 template = pcmk__xe_first_child(cib_resources, PCMK_XE_TEMPLATE,
309 PCMK_XA_ID, template_ref);
310 if (template == NULL) {
311 pcmk__config_err("No template named '%s'", template_ref);
312 return FALSE;
313 }
314
315 new_xml = pcmk__xml_copy(NULL, template);
316 xmlNodeSetName(new_xml, xml_obj->name);
317 crm_xml_add(new_xml, PCMK_XA_ID, id);
318 crm_xml_add(new_xml, PCMK__META_CLONE,
319 crm_element_value(xml_obj, PCMK__META_CLONE));
320
321 template_ops = pcmk__xe_first_child(new_xml, PCMK_XE_OPERATIONS, NULL,
322 NULL);
323
324 for (child_xml = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
325 child_xml != NULL; child_xml = pcmk__xe_next(child_xml, NULL)) {
326
327 xmlNode *new_child = pcmk__xml_copy(new_xml, child_xml);
328
329 if (pcmk__xe_is(new_child, PCMK_XE_OPERATIONS)) {
330 rsc_ops = new_child;
331 }
332 }
333
334 if (template_ops && rsc_ops) {
335 xmlNode *op = NULL;
336 GHashTable *rsc_ops_hash = pcmk__strkey_table(free, NULL);
337
338 for (op = pcmk__xe_first_child(rsc_ops, NULL, NULL, NULL); op != NULL;
339 op = pcmk__xe_next(op, NULL)) {
340
341 char *key = template_op_key(op);
342
343 g_hash_table_insert(rsc_ops_hash, key, op);
344 }
345
346 for (op = pcmk__xe_first_child(template_ops, NULL, NULL, NULL);
347 op != NULL; op = pcmk__xe_next(op, NULL)) {
348
349 char *key = template_op_key(op);
350
351 if (g_hash_table_lookup(rsc_ops_hash, key) == NULL) {
352 pcmk__xml_copy(rsc_ops, op);
353 }
354
355 free(key);
356 }
357
358 if (rsc_ops_hash) {
359 g_hash_table_destroy(rsc_ops_hash);
360 }
361
362 pcmk__xml_free(template_ops);
363 }
364
365
366 *expanded_xml = new_xml;
367
368 #if 0
369 if (!unpack_template(new_xml, expanded_xml, scheduler)) {
370 pcmk__xml_free(*expanded_xml);
371 *expanded_xml = NULL;
372 return FALSE;
373 }
374 #endif
375
376 return TRUE;
377 }
378
379 static gboolean
380 add_template_rsc(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
381 {
382 const char *template_ref = NULL;
383 const char *id = NULL;
384
385 if (xml_obj == NULL) {
386 pcmk__config_err("No resource object for processing resource list "
387 "of template");
388 return FALSE;
389 }
390
391 template_ref = crm_element_value(xml_obj, PCMK_XA_TEMPLATE);
392 if (template_ref == NULL) {
393 return TRUE;
394 }
395
396 id = pcmk__xe_id(xml_obj);
397 if (id == NULL) {
398 pcmk__config_err("'%s' object must have a id", xml_obj->name);
399 return FALSE;
400 }
401
402 if (pcmk__str_eq(template_ref, id, pcmk__str_none)) {
403 pcmk__config_err("The resource object '%s' should not reference itself",
404 id);
405 return FALSE;
406 }
407
408 pcmk__add_idref(scheduler->priv->templates, template_ref, id);
409 return TRUE;
410 }
411
412
413
414
415
416
417
418
419
420
421 static bool
422 detect_unique(const pcmk_resource_t *rsc)
423 {
424 const char *value = g_hash_table_lookup(rsc->priv->meta,
425 PCMK_META_GLOBALLY_UNIQUE);
426
427 if (value == NULL) {
428 value = g_hash_table_lookup(rsc->priv->meta,
429 PCMK_META_CLONE_NODE_MAX);
430 if (value != NULL) {
431 int node_max = 1;
432
433 if ((pcmk__scan_min_int(value, &node_max, 0) == pcmk_rc_ok)
434 && (node_max > 1)) {
435 return true;
436 }
437 }
438 return false;
439 }
440 return crm_is_true(value);
441 }
442
443 static void
444 free_params_table(gpointer data)
445 {
446 g_hash_table_destroy((GHashTable *) data);
447 }
448
449
450
451
452
453
454
455
456
457
458
459
460
461 GHashTable *
462 pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node,
463 pcmk_scheduler_t *scheduler)
464 {
465 GHashTable *params_on_node = NULL;
466
467
468
469
470
471 const char *node_name = "";
472
473
474 if ((rsc == NULL) || (scheduler == NULL)) {
475 return NULL;
476 }
477 if ((node != NULL) && (node->priv->name != NULL)) {
478 node_name = node->priv->name;
479 }
480
481
482 if (rsc->priv->parameter_cache == NULL) {
483 rsc->priv->parameter_cache = pcmk__strikey_table(free,
484 free_params_table);
485 } else {
486 params_on_node = g_hash_table_lookup(rsc->priv->parameter_cache,
487 node_name);
488 }
489
490
491 if (params_on_node == NULL) {
492 params_on_node = pcmk__strkey_table(free, free);
493 get_rsc_attributes(params_on_node, rsc, node, scheduler);
494 g_hash_table_insert(rsc->priv->parameter_cache, strdup(node_name),
495 params_on_node);
496 }
497 return params_on_node;
498 }
499
500
501
502
503
504
505
506
507
508 static void
509 unpack_requires(pcmk_resource_t *rsc, const char *value, bool is_default)
510 {
511 const pcmk_scheduler_t *scheduler = rsc->priv->scheduler;
512
513 if (pcmk__str_eq(value, PCMK_VALUE_NOTHING, pcmk__str_casei)) {
514
515 } else if (pcmk__str_eq(value, PCMK_VALUE_QUORUM, pcmk__str_casei)) {
516 pcmk__set_rsc_flags(rsc, pcmk__rsc_needs_quorum);
517
518 } else if (pcmk__str_eq(value, PCMK_VALUE_FENCING, pcmk__str_casei)) {
519 pcmk__set_rsc_flags(rsc, pcmk__rsc_needs_fencing);
520 if (!pcmk_is_set(scheduler->flags, pcmk__sched_fencing_enabled)) {
521 pcmk__config_warn("%s requires fencing but fencing is disabled",
522 rsc->id);
523 }
524
525 } else if (pcmk__str_eq(value, PCMK_VALUE_UNFENCING, pcmk__str_casei)) {
526 if (pcmk_is_set(rsc->flags, pcmk__rsc_fence_device)) {
527 pcmk__config_warn("Resetting \"" PCMK_META_REQUIRES "\" for %s "
528 "to \"" PCMK_VALUE_QUORUM "\" because fencing "
529 "devices cannot require unfencing", rsc->id);
530 unpack_requires(rsc, PCMK_VALUE_QUORUM, true);
531 return;
532
533 } else if (!pcmk_is_set(scheduler->flags, pcmk__sched_fencing_enabled)) {
534 pcmk__config_warn("Resetting \"" PCMK_META_REQUIRES "\" for %s "
535 "to \"" PCMK_VALUE_QUORUM "\" because fencing is "
536 "disabled", rsc->id);
537 unpack_requires(rsc, PCMK_VALUE_QUORUM, true);
538 return;
539
540 } else {
541 pcmk__set_rsc_flags(rsc, pcmk__rsc_needs_fencing
542 |pcmk__rsc_needs_unfencing);
543 }
544
545 } else {
546 const char *orig_value = value;
547
548 if (pcmk_is_set(rsc->flags, pcmk__rsc_fence_device)) {
549 value = PCMK_VALUE_QUORUM;
550
551 } else if (pcmk__is_primitive(rsc)
552 && xml_contains_remote_node(rsc->priv->xml)) {
553 value = PCMK_VALUE_QUORUM;
554
555 } else if (pcmk_is_set(scheduler->flags, pcmk__sched_enable_unfencing)) {
556 value = PCMK_VALUE_UNFENCING;
557
558 } else if (pcmk_is_set(scheduler->flags, pcmk__sched_fencing_enabled)) {
559 value = PCMK_VALUE_FENCING;
560
561 } else if (scheduler->no_quorum_policy == pcmk_no_quorum_ignore) {
562 value = PCMK_VALUE_NOTHING;
563
564 } else {
565 value = PCMK_VALUE_QUORUM;
566 }
567
568 if (orig_value != NULL) {
569 pcmk__config_err("Resetting '" PCMK_META_REQUIRES "' for %s "
570 "to '%s' because '%s' is not valid",
571 rsc->id, value, orig_value);
572 }
573 unpack_requires(rsc, value, true);
574 return;
575 }
576
577 pcmk__rsc_trace(rsc, "\tRequired to start: %s%s", value,
578 (is_default? " (default)" : ""));
579 }
580
581
582
583
584
585
586
587 static void
588 unpack_priority(pcmk_resource_t *rsc)
589 {
590 const char *value = g_hash_table_lookup(rsc->priv->meta,
591 PCMK_META_PRIORITY);
592 int rc = pcmk_parse_score(value, &(rsc->priv->priority), 0);
593
594 if (rc != pcmk_rc_ok) {
595 pcmk__config_warn("Using default (0) for resource %s "
596 PCMK_META_PRIORITY
597 " because '%s' is not a valid value: %s",
598 rsc->id, value, pcmk_rc_str(rc));
599 }
600 }
601
602
603
604
605
606
607
608 static void
609 unpack_stickiness(pcmk_resource_t *rsc)
610 {
611 const char *value = g_hash_table_lookup(rsc->priv->meta,
612 PCMK_META_RESOURCE_STICKINESS);
613
614 if (pcmk__str_eq(value, PCMK_VALUE_DEFAULT, pcmk__str_casei)) {
615
616 pcmk__config_warn("Support for setting "
617 PCMK_META_RESOURCE_STICKINESS
618 " to the explicit value '" PCMK_VALUE_DEFAULT
619 "' is deprecated and will be removed in a "
620 "future release (just leave it unset)");
621 } else {
622 int rc = pcmk_parse_score(value, &(rsc->priv->stickiness), 0);
623
624 if (rc != pcmk_rc_ok) {
625 pcmk__config_warn("Using default (0) for resource %s "
626 PCMK_META_RESOURCE_STICKINESS
627 " because '%s' is not a valid value: %s",
628 rsc->id, value, pcmk_rc_str(rc));
629 }
630 }
631 }
632
633
634
635
636
637
638
639 static void
640 unpack_migration_threshold(pcmk_resource_t *rsc)
641 {
642 const char *value = g_hash_table_lookup(rsc->priv->meta,
643 PCMK_META_MIGRATION_THRESHOLD);
644
645 if (pcmk__str_eq(value, PCMK_VALUE_DEFAULT, pcmk__str_casei)) {
646
647 pcmk__config_warn("Support for setting "
648 PCMK_META_MIGRATION_THRESHOLD
649 " to the explicit value '" PCMK_VALUE_DEFAULT
650 "' is deprecated and will be removed in a "
651 "future release (just leave it unset)");
652 rsc->priv->ban_after_failures = PCMK_SCORE_INFINITY;
653 } else {
654 int rc = pcmk_parse_score(value, &(rsc->priv->ban_after_failures),
655 PCMK_SCORE_INFINITY);
656
657 if ((rc != pcmk_rc_ok) || (rsc->priv->ban_after_failures < 0)) {
658 pcmk__config_warn("Using default (" PCMK_VALUE_INFINITY
659 ") for resource %s meta-attribute "
660 PCMK_META_MIGRATION_THRESHOLD
661 " because '%s' is not a valid value: %s",
662 rsc->id, value, pcmk_rc_str(rc));
663 rsc->priv->ban_after_failures = PCMK_SCORE_INFINITY;
664 }
665 }
666 }
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685 int
686 pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc,
687 pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
688 {
689 xmlNode *expanded_xml = NULL;
690 xmlNode *ops = NULL;
691 const char *value = NULL;
692 const char *id = NULL;
693 bool guest_node = false;
694 bool remote_node = false;
695 pcmk__resource_private_t *rsc_private = NULL;
696
697 pcmk_rule_input_t rule_input = {
698 .now = NULL,
699 };
700
701 CRM_CHECK(rsc != NULL, return EINVAL);
702 CRM_CHECK((xml_obj != NULL) && (scheduler != NULL),
703 *rsc = NULL;
704 return EINVAL);
705
706 rule_input.now = scheduler->priv->now;
707
708 crm_log_xml_trace(xml_obj, "[raw XML]");
709
710 id = crm_element_value(xml_obj, PCMK_XA_ID);
711 if (id == NULL) {
712 pcmk__config_err("Ignoring <%s> configuration without " PCMK_XA_ID,
713 xml_obj->name);
714 return pcmk_rc_unpack_error;
715 }
716
717 if (unpack_template(xml_obj, &expanded_xml, scheduler) == FALSE) {
718 return pcmk_rc_unpack_error;
719 }
720
721 *rsc = calloc(1, sizeof(pcmk_resource_t));
722 if (*rsc == NULL) {
723 pcmk__sched_err(scheduler,
724 "Unable to allocate memory for resource '%s'", id);
725 return ENOMEM;
726 }
727
728 (*rsc)->priv = calloc(1, sizeof(pcmk__resource_private_t));
729 if ((*rsc)->priv == NULL) {
730 pcmk__sched_err(scheduler,
731 "Unable to allocate memory for resource '%s'", id);
732 free(*rsc);
733 return ENOMEM;
734 }
735 rsc_private = (*rsc)->priv;
736
737 rsc_private->scheduler = scheduler;
738
739 if (expanded_xml) {
740 crm_log_xml_trace(expanded_xml, "[expanded XML]");
741 rsc_private->xml = expanded_xml;
742 rsc_private->orig_xml = xml_obj;
743
744 } else {
745 rsc_private->xml = xml_obj;
746 rsc_private->orig_xml = NULL;
747 }
748
749
750
751 rsc_private->parent = parent;
752
753 ops = pcmk__xe_first_child(rsc_private->xml, PCMK_XE_OPERATIONS, NULL,
754 NULL);
755 rsc_private->ops_xml = pcmk__xe_resolve_idref(ops, scheduler->input);
756
757 rsc_private->variant = get_resource_type((const char *)
758 rsc_private->xml->name);
759 if (rsc_private->variant == pcmk__rsc_variant_unknown) {
760 pcmk__config_err("Ignoring resource '%s' of unknown type '%s'",
761 id, rsc_private->xml->name);
762 common_free(*rsc);
763 *rsc = NULL;
764 return pcmk_rc_unpack_error;
765 }
766
767 rsc_private->meta = pcmk__strkey_table(free, free);
768 rsc_private->utilization = pcmk__strkey_table(free, free);
769 rsc_private->probed_nodes = pcmk__strkey_table(NULL, pcmk__free_node_copy);
770 rsc_private->allowed_nodes = pcmk__strkey_table(NULL, pcmk__free_node_copy);
771
772 value = crm_element_value(rsc_private->xml, PCMK__META_CLONE);
773 if (value) {
774 (*rsc)->id = crm_strdup_printf("%s:%s", id, value);
775 pcmk__insert_meta(rsc_private, PCMK__META_CLONE, value);
776
777 } else {
778 (*rsc)->id = strdup(id);
779 }
780
781 rsc_private->fns = &resource_class_functions[rsc_private->variant];
782
783 get_meta_attributes(rsc_private->meta, *rsc, NULL, scheduler);
784
785 (*rsc)->flags = 0;
786 pcmk__set_rsc_flags(*rsc, pcmk__rsc_unassigned);
787
788 if (!pcmk_is_set(scheduler->flags, pcmk__sched_in_maintenance)) {
789 pcmk__set_rsc_flags(*rsc, pcmk__rsc_managed);
790 }
791
792 rsc_private->orig_role = pcmk_role_stopped;
793 rsc_private->next_role = pcmk_role_unknown;
794
795 unpack_priority(*rsc);
796
797 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_CRITICAL);
798 if ((value == NULL) || crm_is_true(value)) {
799 pcmk__set_rsc_flags(*rsc, pcmk__rsc_critical);
800 }
801
802 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_NOTIFY);
803 if (crm_is_true(value)) {
804 pcmk__set_rsc_flags(*rsc, pcmk__rsc_notify);
805 }
806
807 if (xml_contains_remote_node(rsc_private->xml)) {
808 pcmk__set_rsc_flags(*rsc, pcmk__rsc_is_remote_connection);
809 if (g_hash_table_lookup(rsc_private->meta, PCMK__META_CONTAINER)) {
810 guest_node = true;
811 } else {
812 remote_node = true;
813 }
814 }
815
816 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_ALLOW_MIGRATE);
817 if (crm_is_true(value)) {
818 pcmk__set_rsc_flags(*rsc, pcmk__rsc_migratable);
819 } else if ((value == NULL) && remote_node) {
820
821
822
823
824
825
826
827 pcmk__set_rsc_flags(*rsc, pcmk__rsc_migratable);
828 }
829
830 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_IS_MANAGED);
831 if (value != NULL) {
832 if (pcmk__str_eq(PCMK_VALUE_DEFAULT, value, pcmk__str_casei)) {
833
834 pcmk__config_warn("Support for setting " PCMK_META_IS_MANAGED
835 " to the explicit value '" PCMK_VALUE_DEFAULT
836 "' is deprecated and will be removed in a "
837 "future release (just leave it unset)");
838 } else if (crm_is_true(value)) {
839 pcmk__set_rsc_flags(*rsc, pcmk__rsc_managed);
840 } else {
841 pcmk__clear_rsc_flags(*rsc, pcmk__rsc_managed);
842 }
843 }
844
845 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_MAINTENANCE);
846 if (crm_is_true(value)) {
847 pcmk__clear_rsc_flags(*rsc, pcmk__rsc_managed);
848 pcmk__set_rsc_flags(*rsc, pcmk__rsc_maintenance);
849 }
850 if (pcmk_is_set(scheduler->flags, pcmk__sched_in_maintenance)) {
851 pcmk__clear_rsc_flags(*rsc, pcmk__rsc_managed);
852 pcmk__set_rsc_flags(*rsc, pcmk__rsc_maintenance);
853 }
854
855 if (pcmk__is_clone(pe__const_top_resource(*rsc, false))) {
856 if (detect_unique(*rsc)) {
857 pcmk__set_rsc_flags(*rsc, pcmk__rsc_unique);
858 }
859 if (crm_is_true(g_hash_table_lookup((*rsc)->priv->meta,
860 PCMK_META_PROMOTABLE))) {
861 pcmk__set_rsc_flags(*rsc, pcmk__rsc_promotable);
862 }
863 } else {
864 pcmk__set_rsc_flags(*rsc, pcmk__rsc_unique);
865 }
866
867 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_MULTIPLE_ACTIVE);
868 if (pcmk__str_eq(value, PCMK_VALUE_STOP_ONLY, pcmk__str_casei)) {
869 rsc_private->multiply_active_policy = pcmk__multiply_active_stop;
870 pcmk__rsc_trace(*rsc, "%s multiple running resource recovery: stop only",
871 (*rsc)->id);
872
873 } else if (pcmk__str_eq(value, PCMK_VALUE_BLOCK, pcmk__str_casei)) {
874 rsc_private->multiply_active_policy = pcmk__multiply_active_block;
875 pcmk__rsc_trace(*rsc, "%s multiple running resource recovery: block",
876 (*rsc)->id);
877
878 } else if (pcmk__str_eq(value, PCMK_VALUE_STOP_UNEXPECTED,
879 pcmk__str_casei)) {
880 rsc_private->multiply_active_policy = pcmk__multiply_active_unexpected;
881 pcmk__rsc_trace(*rsc,
882 "%s multiple running resource recovery: "
883 "stop unexpected instances",
884 (*rsc)->id);
885
886 } else {
887 if (!pcmk__str_eq(value, PCMK_VALUE_STOP_START,
888 pcmk__str_casei|pcmk__str_null_matches)) {
889 pcmk__config_warn("%s is not a valid value for "
890 PCMK_META_MULTIPLE_ACTIVE
891 ", using default of "
892 "\"" PCMK_VALUE_STOP_START "\"",
893 value);
894 }
895 rsc_private->multiply_active_policy = pcmk__multiply_active_restart;
896 pcmk__rsc_trace(*rsc,
897 "%s multiple running resource recovery: stop/start",
898 (*rsc)->id);
899 }
900
901 unpack_stickiness(*rsc);
902 unpack_migration_threshold(*rsc);
903
904 if (pcmk__str_eq(crm_element_value(rsc_private->xml, PCMK_XA_CLASS),
905 PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
906 pcmk__set_scheduler_flags(scheduler, pcmk__sched_have_fencing);
907 pcmk__set_rsc_flags(*rsc, pcmk__rsc_fence_device);
908 }
909
910 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_REQUIRES);
911 unpack_requires(*rsc, value, false);
912
913 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_FAILURE_TIMEOUT);
914 if (value != NULL) {
915 pcmk_parse_interval_spec(value, &(rsc_private->failure_expiration_ms));
916 }
917
918 if (remote_node) {
919 GHashTable *params = pe_rsc_params(*rsc, NULL, scheduler);
920
921
922
923
924
925
926
927 value = g_hash_table_lookup(params, PCMK_REMOTE_RA_RECONNECT_INTERVAL);
928 if (value) {
929
930
931 pcmk_parse_interval_spec(value,
932 &(rsc_private->remote_reconnect_ms));
933
934
935
936
937 rsc_private->failure_expiration_ms =
938 rsc_private->remote_reconnect_ms;
939 }
940 }
941
942 get_target_role(*rsc, &(rsc_private->next_role));
943 pcmk__rsc_trace(*rsc, "%s desired next state: %s", (*rsc)->id,
944 (rsc_private->next_role == pcmk_role_unknown)?
945 "default" : pcmk_role_text(rsc_private->next_role));
946
947 if (!rsc_private->fns->unpack(*rsc)) {
948 pcmk__free_resource(*rsc);
949 *rsc = NULL;
950 return pcmk_rc_unpack_error;
951 }
952
953 if (pcmk_is_set(scheduler->flags, pcmk__sched_symmetric_cluster)) {
954
955 resource_location(*rsc, NULL, 0, "symmetric_default", scheduler);
956 } else if (guest_node) {
957
958
959
960 resource_location(*rsc, NULL, 0, "remote_connection_default",
961 scheduler);
962 }
963
964 pcmk__rsc_trace(*rsc, "%s action notification: %s", (*rsc)->id,
965 pcmk_is_set((*rsc)->flags, pcmk__rsc_notify)? "required" : "not required");
966
967 pe__unpack_dataset_nvpairs(rsc_private->xml, PCMK_XE_UTILIZATION,
968 &rule_input, rsc_private->utilization, NULL,
969 scheduler);
970
971 if (expanded_xml) {
972 if (add_template_rsc(xml_obj, scheduler) == FALSE) {
973 pcmk__free_resource(*rsc);
974 *rsc = NULL;
975 return pcmk_rc_unpack_error;
976 }
977 }
978 return pcmk_rc_ok;
979 }
980
981 gboolean
982 is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
983 {
984 pcmk_resource_t *parent = child;
985
986 if (parent == NULL || rsc == NULL) {
987 return FALSE;
988 }
989 while (parent->priv->parent != NULL) {
990 if (parent->priv->parent == rsc) {
991 return TRUE;
992 }
993 parent = parent->priv->parent;
994 }
995 return FALSE;
996 }
997
998 pcmk_resource_t *
999 uber_parent(pcmk_resource_t *rsc)
1000 {
1001 pcmk_resource_t *parent = rsc;
1002
1003 if (parent == NULL) {
1004 return NULL;
1005 }
1006 while ((parent->priv->parent != NULL)
1007 && !pcmk__is_bundle(parent->priv->parent)) {
1008 parent = parent->priv->parent;
1009 }
1010 return parent;
1011 }
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024 const pcmk_resource_t *
1025 pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
1026 {
1027 const pcmk_resource_t *parent = rsc;
1028
1029 if (parent == NULL) {
1030 return NULL;
1031 }
1032 while (parent->priv->parent != NULL) {
1033 if (!include_bundle && pcmk__is_bundle(parent->priv->parent)) {
1034 break;
1035 }
1036 parent = parent->priv->parent;
1037 }
1038 return parent;
1039 }
1040
1041 void
1042 common_free(pcmk_resource_t * rsc)
1043 {
1044 if (rsc == NULL) {
1045 return;
1046 }
1047
1048 pcmk__rsc_trace(rsc, "Freeing %s", rsc->id);
1049
1050 if (rsc->priv->parameter_cache != NULL) {
1051 g_hash_table_destroy(rsc->priv->parameter_cache);
1052 }
1053
1054 if ((rsc->priv->parent == NULL)
1055 && pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
1056
1057 pcmk__xml_free(rsc->priv->xml);
1058 rsc->priv->xml = NULL;
1059 pcmk__xml_free(rsc->priv->orig_xml);
1060 rsc->priv->orig_xml = NULL;
1061
1062 } else if (rsc->priv->orig_xml != NULL) {
1063
1064 pcmk__xml_free(rsc->priv->xml);
1065 rsc->priv->xml = NULL;
1066 }
1067 free(rsc->id);
1068
1069 free(rsc->priv->variant_opaque);
1070 free(rsc->priv->history_id);
1071 free(rsc->priv->pending_action);
1072 pcmk__free_node_copy(rsc->priv->assigned_node);
1073
1074 g_list_free(rsc->priv->actions);
1075 g_list_free(rsc->priv->active_nodes);
1076 g_list_free(rsc->priv->launched);
1077 g_list_free(rsc->priv->dangling_migration_sources);
1078 g_list_free(rsc->priv->with_this_colocations);
1079 g_list_free(rsc->priv->this_with_colocations);
1080 g_list_free(rsc->priv->location_constraints);
1081 g_list_free(rsc->priv->ticket_constraints);
1082
1083 if (rsc->priv->meta != NULL) {
1084 g_hash_table_destroy(rsc->priv->meta);
1085 }
1086 if (rsc->priv->utilization != NULL) {
1087 g_hash_table_destroy(rsc->priv->utilization);
1088 }
1089 if (rsc->priv->probed_nodes != NULL) {
1090 g_hash_table_destroy(rsc->priv->probed_nodes);
1091 }
1092 if (rsc->priv->allowed_nodes != NULL) {
1093 g_hash_table_destroy(rsc->priv->allowed_nodes);
1094 }
1095
1096 free(rsc->priv);
1097
1098 free(rsc);
1099 }
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115 bool
1116 pe__count_active_node(const pcmk_resource_t *rsc, pcmk_node_t *node,
1117 pcmk_node_t **active, unsigned int *count_all,
1118 unsigned int *count_clean)
1119 {
1120 bool keep_looking = false;
1121 bool is_happy = false;
1122
1123 CRM_CHECK((rsc != NULL) && (node != NULL) && (active != NULL),
1124 return false);
1125
1126 is_happy = node->details->online && !node->details->unclean;
1127
1128 if (count_all != NULL) {
1129 ++*count_all;
1130 }
1131 if ((count_clean != NULL) && is_happy) {
1132 ++*count_clean;
1133 }
1134 if ((count_all != NULL) || (count_clean != NULL)) {
1135 keep_looking = true;
1136 }
1137
1138 if (rsc->priv->partial_migration_source != NULL) {
1139 if (pcmk__same_node(node, rsc->priv->partial_migration_source)) {
1140 *active = node;
1141 } else {
1142 keep_looking = true;
1143 }
1144 } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_needs_fencing)) {
1145 if (is_happy && ((*active == NULL) || !(*active)->details->online
1146 || (*active)->details->unclean)) {
1147 *active = node;
1148 } else {
1149 keep_looking = true;
1150 }
1151 }
1152 if (*active == NULL) {
1153 *active = node;
1154 }
1155 return keep_looking;
1156 }
1157
1158
1159 static pcmk_node_t *
1160 active_node(const pcmk_resource_t *rsc, unsigned int *count_all,
1161 unsigned int *count_clean)
1162 {
1163 pcmk_node_t *active = NULL;
1164
1165 if (count_all != NULL) {
1166 *count_all = 0;
1167 }
1168 if (count_clean != NULL) {
1169 *count_clean = 0;
1170 }
1171 if (rsc == NULL) {
1172 return NULL;
1173 }
1174 for (GList *iter = rsc->priv->active_nodes;
1175 iter != NULL; iter = iter->next) {
1176
1177 if (!pe__count_active_node(rsc, (pcmk_node_t *) iter->data, &active,
1178 count_all, count_clean)) {
1179 break;
1180 }
1181 }
1182 return active;
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198 pcmk_node_t *
1199 pe__find_active_requires(const pcmk_resource_t *rsc, unsigned int *count)
1200 {
1201 if (rsc == NULL) {
1202 if (count != NULL) {
1203 *count = 0;
1204 }
1205 return NULL;
1206 }
1207
1208 if (pcmk_is_set(rsc->flags, pcmk__rsc_needs_fencing)) {
1209 return rsc->priv->fns->active_node(rsc, count, NULL);
1210 } else {
1211 return rsc->priv->fns->active_node(rsc, NULL, count);
1212 }
1213 }
1214
1215 void
1216 pe__count_common(pcmk_resource_t *rsc)
1217 {
1218 if (rsc->priv->children != NULL) {
1219 for (GList *item = rsc->priv->children;
1220 item != NULL; item = item->next) {
1221 pcmk_resource_t *child = item->data;
1222
1223 child->priv->fns->count(item->data);
1224 }
1225
1226 } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_removed)
1227 || (rsc->priv->orig_role > pcmk_role_stopped)) {
1228 rsc->priv->scheduler->priv->ninstances++;
1229 if (pe__resource_is_disabled(rsc)) {
1230 rsc->priv->scheduler->priv->disabled_resources++;
1231 }
1232 if (pcmk_is_set(rsc->flags, pcmk__rsc_blocked)) {
1233 rsc->priv->scheduler->priv->blocked_resources++;
1234 }
1235 }
1236 }
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246 void
1247 pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
1248 {
1249 pcmk__assert((rsc != NULL) && (why != NULL));
1250 if (rsc->priv->next_role != role) {
1251 pcmk__rsc_trace(rsc, "Resetting next role for %s from %s to %s (%s)",
1252 rsc->id, pcmk_role_text(rsc->priv->next_role),
1253 pcmk_role_text(role), why);
1254 rsc->priv->next_role = role;
1255 }
1256 }