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