pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
complex.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2025 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <libxml/tree.h> // xmlNode
13
15#include <crm/common/xml.h>
18
19#include "pe_status_private.h"
20
21void populate_hash(xmlNode * nvpair_list, GHashTable * hash, const char **attrs, int attrs_length);
22
23static pcmk_node_t *active_node(const pcmk_resource_t *rsc,
24 unsigned int *count_all,
25 unsigned int *count_clean);
26
27static pcmk__rsc_methods_t resource_class_functions[] = {
28 {
37 active_node,
39 },
40 {
49 active_node,
51 },
52 {
61 active_node,
63 },
64 {
75 }
76};
77
78static enum pcmk__rsc_variant
79get_resource_type(const char *name)
80{
81 if (pcmk__str_eq(name, PCMK_XE_PRIMITIVE, pcmk__str_casei)) {
83
84 } else if (pcmk__str_eq(name, PCMK_XE_GROUP, pcmk__str_casei)) {
86
87 } else if (pcmk__str_eq(name, PCMK_XE_CLONE, pcmk__str_casei)) {
89
90 } else if (pcmk__str_eq(name, PCMK_XE_BUNDLE, pcmk__str_casei)) {
92 }
93
95}
96
108static void
109dup_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 // @COMPAT Deprecated since 2.1.8
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
125static void
126expand_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 /* Search all parent resources, get the fixed value of
138 * PCMK_XE_META_ATTRIBUTES set only in the original xml, and stack it in the
139 * hash table. The fixed value of the lower parent resource takes precedence
140 * and is not overwritten.
141 */
142 while(p != NULL) {
143 /* A hash table for comparison is generated, including the id-ref. */
145 rule_input, parent_orig_meta, NULL,
146 scheduler);
147 p = p->priv->parent;
148 }
149
150 if (parent_orig_meta != NULL) {
151 // This will not overwrite any values already existing for child
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 * \brief Get fully evaluated resource meta-attributes
165 *
166 * \param[in,out] meta_hash Where to store evaluated meta-attributes
167 * \param[in] rsc Resource to get meta-attributes for
168 * \param[in] node Ignored
169 * \param[in,out] scheduler Scheduler data
170 */
171void
172get_meta_attributes(GHashTable * meta_hash, pcmk_resource_t * rsc,
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
192 &rule_input, meta_hash, NULL, scheduler);
193
194 /* Set the PCMK_XE_META_ATTRIBUTES explicitly set in the parent resource to
195 * the hash table of the child resource. If it is already explicitly set as
196 * a child, it will not be overwritten.
197 */
198 if (rsc->priv->parent != NULL) {
199 expand_parents_fixed_nvpairs(rsc, &rule_input, meta_hash, scheduler);
200 }
201
202 /* check the defaults */
204 PCMK_XE_META_ATTRIBUTES, &rule_input, meta_hash,
205 NULL, scheduler);
206
207 /* If there is PCMK_XE_META_ATTRIBUTES that the parent resource has not
208 * explicitly set, set a value that is not set from PCMK_XE_RSC_DEFAULTS
209 * either. The values already set up to this point will not be overwritten.
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
225void
226get_rsc_attributes(GHashTable *instance_attrs, const pcmk_resource_t *rsc,
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 // Evaluate resource's own values, then its ancestors' values
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
249static char *
250template_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)
259 role = PCMK__ROLE_UNKNOWN;
260 }
261
262 key = crm_strdup_printf("%s-%s", name, role);
263 return key;
264}
265
266static gboolean
267unpack_template(xmlNode *xml_obj, xmlNode **expanded_xml,
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,
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);
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 /*pcmk__xml_free(*expanded_xml); */
366 *expanded_xml = new_xml;
367
368#if 0 /* Disable multi-level templates for now */
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
379static gboolean
380add_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
421static bool
422detect_unique(const pcmk_resource_t *rsc)
423{
424 const char *value = g_hash_table_lookup(rsc->priv->meta,
426
427 if (value == NULL) { // Default to true if clone-node-max > 1
428 value = g_hash_table_lookup(rsc->priv->meta,
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
443static void
444free_params_table(gpointer data)
445{
446 g_hash_table_destroy((GHashTable *) data);
447}
448
461GHashTable *
464{
465 GHashTable *params_on_node = NULL;
466
467 /* A NULL node is used to request the resource's default parameters
468 * (not evaluated for node), but we always want something non-NULL
469 * as a hash table key.
470 */
471 const char *node_name = "";
472
473 // Sanity check
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 // Find the parameter table for given node
482 if (rsc->priv->parameter_cache == NULL) {
484 free_params_table);
485 } else {
486 params_on_node = g_hash_table_lookup(rsc->priv->parameter_cache,
487 node_name);
488 }
489
490 // If none exists yet, create one with parameters evaluated for node
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
508static void
509unpack_requires(pcmk_resource_t *rsc, const char *value, bool is_default)
510{
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)) {
517
518 } else if (pcmk__str_eq(value, PCMK_VALUE_FENCING, pcmk__str_casei)) {
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)) {
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
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 {
543 }
544
545 } else {
546 const char *orig_value = value;
547
549 value = PCMK_VALUE_QUORUM;
550
551 } else if (pcmk__is_primitive(rsc)
553 value = PCMK_VALUE_QUORUM;
554
556 value = PCMK_VALUE_UNFENCING;
557
559 value = PCMK_VALUE_FENCING;
560
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
587static void
588unpack_priority(pcmk_resource_t *rsc)
589{
590 const char *value = g_hash_table_lookup(rsc->priv->meta,
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 "
597 " because '%s' is not a valid value: %s",
598 rsc->id, value, pcmk_rc_str(rc));
599 }
600}
601
608static void
609unpack_stickiness(pcmk_resource_t *rsc)
610{
611 const char *value = g_hash_table_lookup(rsc->priv->meta,
613
614 if (pcmk__str_eq(value, PCMK_VALUE_DEFAULT, pcmk__str_casei)) {
615 // @COMPAT Deprecated since 2.1.8
616 pcmk__config_warn("Support for setting "
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 "
627 " because '%s' is not a valid value: %s",
628 rsc->id, value, pcmk_rc_str(rc));
629 }
630 }
631}
632
639static void
640unpack_migration_threshold(pcmk_resource_t *rsc)
641{
642 const char *value = g_hash_table_lookup(rsc->priv->meta,
644
645 if (pcmk__str_eq(value, PCMK_VALUE_DEFAULT, pcmk__str_casei)) {
646 // @COMPAT Deprecated since 2.1.8
647 pcmk__config_warn("Support for setting "
649 " to the explicit value '" PCMK_VALUE_DEFAULT
650 "' is deprecated and will be removed in a "
651 "future release (just leave it unset)");
653 } else {
654 int rc = pcmk_parse_score(value, &(rsc->priv->ban_after_failures),
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 "
661 " because '%s' is not a valid value: %s",
662 rsc->id, value, pcmk_rc_str(rc));
664 }
665 }
666}
667
685int
686pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc,
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);
715 }
716
717 if (unpack_template(xml_obj, &expanded_xml, scheduler) == FALSE) {
719 }
720
721 *rsc = calloc(1, sizeof(pcmk_resource_t));
722 if (*rsc == NULL) {
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) {
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 /* Do not use xml_obj from here on, use (*rsc)->xml in case templates are involved */
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;
765 }
766
767 rsc_private->meta = pcmk__strkey_table(free, free);
768 rsc_private->utilization = pcmk__strkey_table(free, free);
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;
787
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)) {
800 }
801
802 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_NOTIFY);
803 if (crm_is_true(value)) {
805 }
806
807 if (xml_contains_remote_node(rsc_private->xml)) {
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)) {
819 } else if ((value == NULL) && remote_node) {
820 /* By default, we want remote nodes to be able
821 * to float around the cluster without having to stop all the
822 * resources within the remote-node before moving. Allowing
823 * migration support enables this feature. If this ever causes
824 * problems, migration support can be explicitly turned off with
825 * PCMK_META_ALLOW_MIGRATE=false.
826 */
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 // @COMPAT Deprecated since 2.1.8
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)) {
840 } else {
842 }
843 }
844
845 value = g_hash_table_lookup(rsc_private->meta, PCMK_META_MAINTENANCE);
846 if (crm_is_true(value)) {
849 }
853 }
854
855 if (pcmk__is_clone(pe__const_top_resource(*rsc, false))) {
856 if (detect_unique(*rsc)) {
858 }
859 if (crm_is_true(g_hash_table_lookup((*rsc)->priv->meta,
862 }
863 } else {
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)) {
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)) {
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,
881 pcmk__rsc_trace(*rsc,
882 "%s multiple running resource recovery: "
883 "stop unexpected instances",
884 (*rsc)->id);
885
886 } else { // PCMK_VALUE_STOP_START
887 if (!pcmk__str_eq(value, PCMK_VALUE_STOP_START,
889 pcmk__config_warn("%s is not a valid value for "
891 ", using default of "
892 "\"" PCMK_VALUE_STOP_START "\"",
893 value);
894 }
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),
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 /* Grabbing the value now means that any rules based on node attributes
922 * will evaluate to false, so such rules should not be used with
923 * PCMK_REMOTE_RA_RECONNECT_INTERVAL.
924 *
925 * @TODO Evaluate per node before using
926 */
927 value = g_hash_table_lookup(params, PCMK_REMOTE_RA_RECONNECT_INTERVAL);
928 if (value) {
929 /* reconnect delay works by setting failure_timeout and preventing the
930 * connection from starting until the failure is cleared. */
932 &(rsc_private->remote_reconnect_ms));
933
934 /* We want to override any default failure_timeout in use when remote
935 * PCMK_REMOTE_RA_RECONNECT_INTERVAL is in use.
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)) {
949 *rsc = NULL;
951 }
952
954 // This tag must stay exactly the same because it is tested elsewhere
955 resource_location(*rsc, NULL, 0, "symmetric_default", scheduler);
956 } else if (guest_node) {
957 /* remote resources tied to a container resource must always be allowed
958 * to opt-in to the cluster. Whether the connection resource is actually
959 * allowed to be placed on a node is dependent on the container resource */
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
968 &rule_input, rsc_private->utilization, NULL,
969 scheduler);
970
971 if (expanded_xml) {
972 if (add_template_rsc(xml_obj, scheduler) == FALSE) {
974 *rsc = NULL;
976 }
977 }
978 return pcmk_rc_ok;
979}
980
981gboolean
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
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
1024const pcmk_resource_t *
1025pe__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
1041void
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)
1056
1057 pcmk__xml_free(rsc->priv->xml);
1058 rsc->priv->xml = NULL;
1060 rsc->priv->orig_xml = NULL;
1061
1062 } else if (rsc->priv->orig_xml != NULL) {
1063 // rsc->private->xml was expanded from a template
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);
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
1115bool
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; // We're counting, so go through entire list
1136 }
1137
1138 if (rsc->priv->partial_migration_source != NULL) {
1139 if (pcmk__same_node(node, rsc->priv->partial_migration_source)) {
1140 *active = node; // This is the migration source
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; // This is the first clean node
1148 } else {
1149 keep_looking = true;
1150 }
1151 }
1152 if (*active == NULL) {
1153 *active = node; // This is the first node checked
1154 }
1155 return keep_looking;
1156}
1157
1158// Shared implementation of pcmk__rsc_methods_t:active_node()
1159static pcmk_node_t *
1160active_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; // Don't waste time iterating if we don't have to
1180 }
1181 }
1182 return active;
1183}
1184
1199pe__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
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
1215void
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)) {
1231 }
1232 if (pcmk_is_set(rsc->flags, pcmk__rsc_blocked)) {
1234 }
1235 }
1236}
1237
1246void
1247pe__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}
#define PCMK_RESOURCE_CLASS_STONITH
Definition agents.h:31
unsigned int pe__bundle_max_per_node(const pcmk_resource_t *rsc)
Definition bundle.c:2092
pcmk_node_t * pe__bundle_active_node(const pcmk_resource_t *rsc, unsigned int *count_all, unsigned int *count_clean)
Definition bundle.c:2008
const char * parent
Definition cib.c:27
const char * name
Definition cib.c:26
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
Definition clone.c:1253
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
void get_rsc_attributes(GHashTable *instance_attrs, const pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get final values of a resource's instance attributes.
Definition complex.c:226
pcmk_node_t * pe__find_active_requires(const pcmk_resource_t *rsc, unsigned int *count)
Definition complex.c:1199
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1025
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition complex.c:999
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition complex.c:982
GHashTable * pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get a table of resource parameters.
Definition complex.c:462
void populate_hash(xmlNode *nvpair_list, GHashTable *hash, const char **attrs, int attrs_length)
void get_meta_attributes(GHashTable *meta_hash, pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Definition complex.c:172
bool pe__count_active_node(const pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_node_t **active, unsigned int *count_all, unsigned int *count_clean)
Definition complex.c:1116
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
Definition complex.c:686
void pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition complex.c:1247
void common_free(pcmk_resource_t *rsc)
Definition complex.c:1042
void pe__count_common(pcmk_resource_t *rsc)
Definition complex.c:1216
char data[0]
Definition cpg.c:10
unsigned int pe__group_max_per_node(const pcmk_resource_t *rsc)
Definition group.c:466
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define crm_log_xml_trace(xml, text)
Definition logging.h:378
#define LOG_TRACE
Definition logging.h:38
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
unsigned int pe__primitive_max_per_node(const pcmk_resource_t *rsc)
Definition native.c:1153
pcmk_scheduler_t * scheduler
void pcmk__free_node_copy(void *data)
Definition nodes.c:64
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_PRIORITY
Definition options.h:101
#define PCMK_META_PROMOTABLE
Definition options.h:102
#define PCMK_VALUE_STOP_UNEXPECTED
Definition options.h:216
#define PCMK_META_RESOURCE_STICKINESS
Definition options.h:112
#define PCMK_META_MIGRATION_THRESHOLD
Definition options.h:96
#define PCMK_META_REQUIRES
Definition options.h:111
#define PCMK_META_CLONE_NODE_MAX
Definition options.h:85
#define PCMK_VALUE_STOP_START
Definition options.h:215
#define PCMK_VALUE_FENCING
Definition options.h:156
#define PCMK_META_CRITICAL
Definition options.h:87
#define PCMK_REMOTE_RA_RECONNECT_INTERVAL
Definition options.h:125
#define PCMK_META_NOTIFY
Definition options.h:98
#define PCMK_META_FAILURE_TIMEOUT
Definition options.h:89
#define PCMK_VALUE_QUORUM
Definition options.h:198
#define PCMK_META_IS_MANAGED
Definition options.h:93
#define PCMK_META_ALLOW_MIGRATE
Definition options.h:81
#define PCMK_META_GLOBALLY_UNIQUE
Definition options.h:90
#define PCMK_VALUE_BLOCK
Definition options.h:136
#define PCMK_VALUE_STOP_ONLY
Definition options.h:214
#define PCMK_VALUE_DEFAULT
Definition options.h:144
#define PCMK_META_MAINTENANCE
Definition options.h:95
#define PCMK_VALUE_UNFENCING
Definition options.h:220
#define PCMK_VALUE_INFINITY
Definition options.h:165
#define PCMK_VALUE_NOTHING
Definition options.h:183
#define PCMK_META_MULTIPLE_ACTIVE
Definition options.h:97
#define PCMK__META_CONTAINER
#define PCMK__META_CLONE
bool clone_active(const pcmk_resource_t *rsc, bool all)
Definition clone.c:445
enum rsc_role_e pe__bundle_resource_state(const pcmk_resource_t *rsc, bool current)
Definition bundle.c:1884
gboolean get_target_role(const pcmk_resource_t *rsc, enum rsc_role_e *role)
Definition utils.c:435
bool pe__bundle_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
Definition bundle.c:1934
void group_free(pcmk_resource_t *rsc)
Definition group.c:382
bool native_unpack(pcmk_resource_t *rsc)
Definition native.c:205
bool group_active(const pcmk_resource_t *rsc, bool all)
Definition group.c:235
void pe__count_bundle(pcmk_resource_t *rsc)
Definition bundle.c:1910
bool native_active(const pcmk_resource_t *rsc, bool all)
Definition native.c:325
void native_free(pcmk_resource_t *rsc)
Definition native.c:867
bool pe__group_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
Definition group.c:426
enum rsc_role_e group_resource_state(const pcmk_resource_t *rsc, bool current)
Definition group.c:405
void resource_location(pcmk_resource_t *rsc, const pcmk_node_t *node, int score, const char *tag, pcmk_scheduler_t *scheduler)
Definition utils.c:398
void clone_free(pcmk_resource_t *rsc)
Definition clone.c:917
void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, const pcmk_rule_input_t *rule_input, GHashTable *hash, const char *always_first, pcmk_scheduler_t *scheduler)
Definition utils.c:698
bool clone_unpack(pcmk_resource_t *rsc)
Definition clone.c:323
bool pe__native_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
Definition native.c:1129
pcmk_node_t * native_location(const pcmk_resource_t *rsc, GList **list, uint32_t target)
Definition native.c:897
pcmk_resource_t * native_find_rsc(pcmk_resource_t *rsc, const char *id, const pcmk_node_t *node, uint32_t flags)
Definition native.c:270
bool pe__unpack_bundle(pcmk_resource_t *rsc)
Definition bundle.c:957
bool pe__bundle_active(const pcmk_resource_t *rsc, bool all)
Definition bundle.c:1325
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
Definition utils.c:728
bool pe__clone_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
Definition clone.c:995
bool group_unpack(pcmk_resource_t *rsc)
Definition group.c:184
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, bool current)
Definition clone.c:953
enum rsc_role_e native_resource_state(const pcmk_resource_t *rsc, bool current)
Definition native.c:874
void pe__free_bundle(pcmk_resource_t *rsc)
Definition bundle.c:1850
bool xml_contains_remote_node(xmlNode *xml)
Definition remote.c:49
@ pcmk__rsc_migratable
@ pcmk__rsc_managed
@ pcmk__rsc_needs_quorum
@ pcmk__rsc_unassigned
@ pcmk__rsc_needs_unfencing
@ pcmk__rsc_maintenance
@ pcmk__rsc_blocked
@ pcmk__rsc_unique
@ pcmk__rsc_removed
@ pcmk__rsc_promotable
@ pcmk__rsc_fence_device
@ pcmk__rsc_needs_fencing
@ pcmk__rsc_notify
@ pcmk__rsc_is_remote_connection
@ pcmk__rsc_critical
#define pcmk__set_rsc_flags(resource, flags_to_set)
pcmk__rsc_variant
Resource variants supported by Pacemaker.
@ pcmk__rsc_variant_group
Group resource.
@ pcmk__rsc_variant_clone
Clone resource.
@ pcmk__rsc_variant_unknown
Unknown resource variant.
@ pcmk__rsc_variant_primitive
Primitive resource.
@ pcmk__rsc_variant_bundle
Bundle resource.
void pcmk__free_resource(gpointer user_data)
Definition resources.c:25
@ pcmk__multiply_active_restart
Stop on all, start on desired.
@ pcmk__multiply_active_block
Do nothing to resource.
@ pcmk__multiply_active_stop
Stop on all and leave stopped.
@ pcmk__multiply_active_unexpected
Stop unexpected instances.
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:617
@ pcmk_rc_ok
Definition results.h:159
@ pcmk_rc_unpack_error
Definition results.h:122
#define pcmk__assert(expr)
#define PCMK_ROLE_STARTED
Definition roles.h:26
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition roles.c:23
rsc_role_e
Definition roles.h:34
@ pcmk_role_unknown
Resource role is unknown.
Definition roles.h:35
@ pcmk_role_stopped
Stopped.
Definition roles.h:36
#define PCMK_ROLE_UNPROMOTED
Definition roles.h:27
#define PCMK__ROLE_UNPROMOTED_LEGACY
#define PCMK__ROLE_UNKNOWN
@ pcmk_no_quorum_ignore
Act as if partition still holds quorum.
Definition scheduler.h:41
#define pcmk__sched_err(scheduler, fmt...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__set_scheduler_flags(scheduler, flags_to_set)
@ pcmk__sched_in_maintenance
@ pcmk__sched_enable_unfencing
@ pcmk__sched_fencing_enabled
@ pcmk__sched_symmetric_cluster
@ pcmk__sched_have_fencing
int pcmk_parse_score(const char *score_s, int *score, int default_score)
Parse an integer score from a string.
Definition scores.c:34
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:26
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
Definition strings.c:452
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition strings.c:490
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:703
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition strings.c:116
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:685
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1029
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
GHashTable * pcmk__strikey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:741
gboolean online
Definition nodes.h:50
gboolean unclean
Definition nodes.h:58
pcmk_scheduler_t * scheduler
pcmk_node_t * partial_migration_source
enum pcmk__multiply_active multiply_active_policy
enum pcmk__rsc_variant variant
const pcmk__rsc_methods_t * fns
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
Resource object methods.
bool(* unpack)(pcmk_resource_t *rsc)
pcmk_node_t *(* active_node)(const pcmk_resource_t *rsc, unsigned int *count_all, unsigned int *count_clean)
void(* count)(pcmk_resource_t *rsc)
pcmk__scheduler_private_t * priv
Definition scheduler.h:99
enum pe_quorum_policy no_quorum_policy
Definition scheduler.h:93
xmlNode * input
Definition scheduler.h:81
uint64_t flags
Definition scheduler.h:89
pcmk__node_private_t * priv
Definition nodes.h:85
struct pcmk__node_details * details
Definition nodes.h:82
Data used to evaluate a rule (any NULL items are ignored)
Definition rules.h:57
GHashTable * node_attrs
Definition rules.h:77
const crm_time_t * now
Current time for rule evaluation purposes.
Definition rules.h:59
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_resolve_idref(xmlNode *xml, xmlNode *search)
Definition xml_idref.c:85
void pcmk__add_idref(GHashTable *table, const char *id, const char *referrer)
Definition xml_idref.c:32
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:832
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
#define PCMK_XE_UTILIZATION
Definition xml_names.h:217
#define PCMK_XE_BUNDLE
Definition xml_names.h:72
#define PCMK_XA_CLASS
Definition xml_names.h:246
#define PCMK_XE_GROUP
Definition xml_names.h:119
#define PCMK_XA_ID
Definition xml_names.h:301
#define PCMK_XA_ROLE
Definition xml_names.h:387
#define PCMK_XE_RESOURCES
Definition xml_names.h:179
#define PCMK_XA_PROVIDER
Definition xml_names.h:364
#define PCMK_XA_TEMPLATE
Definition xml_names.h:425
#define PCMK_XE_INSTANCE_ATTRIBUTES
Definition xml_names.h:122
#define PCMK_XE_META_ATTRIBUTES
Definition xml_names.h:130
#define PCMK_XE_CLONE
Definition xml_names.h:80
#define PCMK_XE_PRIMITIVE
Definition xml_names.h:164
#define PCMK_XA_TYPE
Definition xml_names.h:430
#define PCMK_XE_TEMPLATE
Definition xml_names.h:211
#define PCMK_XA_NAME
Definition xml_names.h:330
#define PCMK_XE_OPERATIONS
Definition xml_names.h:151
xmlNode * pcmk__xpath_find_one(xmlDoc *doc, const char *path, uint8_t level)
Definition xpath.c:206