pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_location.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2024 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 General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdbool.h>
13#include <glib.h>
14
15#include <crm/crm.h>
17#include <crm/pengine/status.h>
18#include <crm/pengine/rules.h>
19#include <pacemaker-internal.h>
20
22
23static int
24get_node_score(const char *rule, const char *score, bool raw,
25 pcmk_node_t *node, pcmk_resource_t *rsc)
26{
27 int score_f = 0;
28
29 if (score == NULL) {
30 pcmk__config_warn("Rule %s: no score specified (assuming 0)", rule);
31
32 } else if (raw) {
33 score_f = char2score(score);
34
35 } else {
36 const char *target = NULL;
37 const char *attr_score = NULL;
38
39 target = g_hash_table_lookup(rsc->meta,
41
42 attr_score = pcmk__node_attr(node, score, target,
44 if (attr_score == NULL) {
45 crm_debug("Rule %s: %s did not have a value for %s",
46 rule, pcmk__node_name(node), score);
47 score_f = -PCMK_SCORE_INFINITY;
48
49 } else {
50 crm_debug("Rule %s: %s had value %s for %s",
51 rule, pcmk__node_name(node), attr_score, score);
52 score_f = char2score(attr_score);
53 }
54 }
55 return score_f;
56}
57
67static bool
68parse_location_role(const char *role_spec, enum rsc_role_e *role)
69{
70 if (role_spec == NULL) {
71 *role = pcmk_role_unknown;
72 return true;
73 }
74
75 *role = pcmk_parse_role(role_spec);
76 switch (*role) {
78 return false;
79
82 /* Any promotable clone instance cannot be promoted without being in
83 * the unpromoted role first. Therefore, any constraint for the
84 * started or unpromoted role applies to every role.
85 */
86 *role = pcmk_role_unknown;
87 break;
88
89 default:
90 break;
91 }
92 return true;
93}
94
110static bool
111generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml,
112 const char *discovery, crm_time_t *next_change,
113 pcmk_rule_input_t *rule_input)
114{
115 const char *rule_id = NULL;
116 const char *score = NULL;
117 const char *boolean = NULL;
118 const char *role_spec = NULL;
119
120 GList *iter = NULL;
121
122 bool raw_score = true;
123 bool score_allocated = false;
124
125 pcmk__location_t *location_rule = NULL;
126 enum rsc_role_e role = pcmk_role_unknown;
128
129 rule_xml = expand_idref(rule_xml, rsc->cluster->input);
130 if (rule_xml == NULL) {
131 return false; // Error already logged
132 }
133
134 rule_id = crm_element_value(rule_xml, PCMK_XA_ID);
135 if (rule_id == NULL) {
136 pcmk__config_err("Ignoring " PCMK_XE_RULE " without " PCMK_XA_ID
137 " in location constraint");
138 return false;
139 }
140
141 boolean = crm_element_value(rule_xml, PCMK_XA_BOOLEAN_OP);
142 role_spec = crm_element_value(rule_xml, PCMK_XA_ROLE);
143
144 if (parse_location_role(role_spec, &role)) {
145 crm_trace("Setting rule %s role filter to %s", rule_id, role_spec);
146 } else {
147 pcmk__config_err("Ignoring rule %s: Invalid " PCMK_XA_ROLE " '%s'",
148 rule_id, role_spec);
149 return false;
150 }
151
152 crm_trace("Processing location constraint rule %s", rule_id);
153
154 score = crm_element_value(rule_xml, PCMK_XA_SCORE);
155 if (score == NULL) {
157 if (score != NULL) {
158 raw_score = false;
159 }
160 }
161
162 combine = pcmk__parse_combine(boolean);
163 switch (combine) {
165 case pcmk__combine_or:
166 break;
167
168 default:
169 /* @COMPAT When we can break behavioral backward compatibility,
170 * return false
171 */
172 pcmk__config_warn("Location constraint rule %s has invalid "
173 PCMK_XA_BOOLEAN_OP " value '%s', using default "
174 "'" PCMK_VALUE_AND "'",
175 rule_id, boolean);
176 combine = pcmk__combine_and;
177 break;
178 }
179
180 location_rule = pcmk__new_location(rule_id, rsc, 0, discovery, NULL);
181 CRM_CHECK(location_rule != NULL, return NULL);
182
183 location_rule->role_filter = role;
184
185 if ((rule_input->rsc_id != NULL) && (rule_input->rsc_id_nmatches > 0)
186 && !raw_score) {
187
188 char *result = pcmk__replace_submatches(score, rule_input->rsc_id,
189 rule_input->rsc_id_submatches,
190 rule_input->rsc_id_nmatches);
191
192 if (result != NULL) {
193 score = result;
194 score_allocated = true;
195 }
196 }
197
198 for (iter = rsc->cluster->nodes; iter != NULL; iter = iter->next) {
199 pcmk_node_t *node = iter->data;
200
201 rule_input->node_attrs = node->details->attrs;
202 rule_input->rsc_params = pe_rsc_params(rsc, node, rsc->cluster);
203
204 if (pcmk_evaluate_rule(rule_xml, rule_input,
205 next_change) == pcmk_rc_ok) {
207
208 location_rule->nodes = g_list_prepend(location_rule->nodes, local);
209 local->weight = get_node_score(rule_id, score, raw_score, node,
210 rsc);
211 crm_trace("%s has score %s after %s", pcmk__node_name(node),
212 pcmk_readable_score(local->weight), rule_id);
213 }
214 }
215
216 if (score_allocated) {
217 free((char *)score);
218 }
219
220 if (location_rule->nodes == NULL) {
221 crm_trace("No matching nodes for location constraint rule %s", rule_id);
222 } else {
223 crm_trace("Location constraint rule %s matched %d nodes",
224 rule_id, g_list_length(location_rule->nodes));
225 }
226 return true;
227}
228
229static void
230unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc,
231 const char *role_spec, const char *score,
232 char *rsc_id_match, int rsc_id_nmatches,
233 regmatch_t *rsc_id_submatches)
234{
235 const char *rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
236 const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
237 const char *node = crm_element_value(xml_obj, PCMK_XE_NODE);
238 const char *discovery = crm_element_value(xml_obj,
240
241 if (rsc == NULL) {
242 pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
243 "does not exist", id, rsc_id);
244 return;
245 }
246
247 if (score == NULL) {
248 score = crm_element_value(xml_obj, PCMK_XA_SCORE);
249 }
250
251 if ((node != NULL) && (score != NULL)) {
252 int score_i = char2score(score);
253 pcmk_node_t *match = pcmk_find_node(rsc->cluster, node);
254 enum rsc_role_e role = pcmk_role_unknown;
255 pcmk__location_t *location = NULL;
256
257 if (match == NULL) {
258 crm_info("Ignoring location constraint %s "
259 "because '%s' is not a known node",
260 pcmk__s(id, "without ID"), node);
261 return;
262 }
263
264 if (role_spec == NULL) {
265 role_spec = crm_element_value(xml_obj, PCMK_XA_ROLE);
266 }
267 if (parse_location_role(role_spec, &role)) {
268 crm_trace("Setting location constraint %s role filter: %s",
269 id, role_spec);
270 } else {
271 /* @COMPAT The previous behavior of creating the constraint ignoring
272 * the role is retained for now, but we should ignore the entire
273 * constraint when we can break backward compatibility.
274 */
275 pcmk__config_err("Ignoring role in constraint %s: "
276 "Invalid value '%s'", id, role_spec);
277 }
278
279 location = pcmk__new_location(id, rsc, score_i, discovery, match);
280 if (location == NULL) {
281 return; // Error already logged
282 }
283 location->role_filter = role;
284
285 } else {
286 bool empty = true;
287 crm_time_t *next_change = crm_time_new_undefined();
288 pcmk_rule_input_t rule_input = {
289 .now = rsc->cluster->now,
290 .rsc_meta = rsc->meta,
291 .rsc_id = rsc_id_match,
292 .rsc_id_submatches = rsc_id_submatches,
293 .rsc_id_nmatches = rsc_id_nmatches,
294 };
295
296 /* This loop is logically parallel to pcmk__evaluate_rules(), except
297 * instead of checking whether any rule is active, we set up location
298 * constraints for each active rule.
299 *
300 * @COMPAT When we can break backward compatibility, limit location
301 * constraints to a single rule, for consistency with other contexts.
302 * Since a rule may contain other rules, this does not prohibit any
303 * existing use cases.
304 */
305 for (xmlNode *rule_xml = pcmk__xe_first_child(xml_obj, PCMK_XE_RULE,
306 NULL, NULL);
307 rule_xml != NULL; rule_xml = pcmk__xe_next_same(rule_xml)) {
308
309 if (generate_location_rule(rsc, rule_xml, discovery, next_change,
310 &rule_input)) {
311 if (empty) {
312 empty = false;
313 continue;
314 }
316 "Support for multiple " PCMK_XE_RULE
317 " elements in a location constraint is "
318 "deprecated and will be removed in a future "
319 "release (use a single new rule combining the "
320 "previous rules with " PCMK_XA_BOOLEAN_OP
321 " set to '" PCMK_VALUE_OR "' instead)");
322 }
323 }
324
325 if (empty) {
326 pcmk__config_err("Ignoring constraint '%s' because it contains "
327 "no valid rules", id);
328 }
329
330 /* If there is a point in the future when the evaluation of a rule will
331 * change, make sure the scheduler is re-run by that time.
332 */
333 if (crm_time_is_defined(next_change)) {
334 time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change);
335
337 "location rule evaluation");
338 }
339 crm_time_free(next_change);
340 }
341}
342
343static void
344unpack_simple_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
345{
346 const char *id = crm_element_value(xml_obj, PCMK_XA_ID);
347 const char *value = crm_element_value(xml_obj, PCMK_XA_RSC);
348
349 if (value) {
350 pcmk_resource_t *rsc;
351
353 unpack_rsc_location(xml_obj, rsc, NULL, NULL, NULL, 0, NULL);
354 }
355
356 value = crm_element_value(xml_obj, PCMK_XA_RSC_PATTERN);
357 if (value) {
358 regex_t regex;
359 bool invert = false;
360
361 if (value[0] == '!') {
362 value++;
363 invert = true;
364 }
365
366 if (regcomp(&regex, value, REG_EXTENDED) != 0) {
367 pcmk__config_err("Ignoring constraint '%s' because "
369 " has invalid value '%s'", id, value);
370 return;
371 }
372
373 for (GList *iter = scheduler->resources; iter != NULL;
374 iter = iter->next) {
375
376 pcmk_resource_t *r = iter->data;
377 int nregs = 0;
378 regmatch_t *pmatch = NULL;
379 int status;
380
381 if (regex.re_nsub > 0) {
382 nregs = regex.re_nsub + 1;
383 } else {
384 nregs = 1;
385 }
386 pmatch = pcmk__assert_alloc(nregs, sizeof(regmatch_t));
387
388 status = regexec(&regex, r->id, nregs, pmatch, 0);
389
390 if (!invert && (status == 0)) {
391 crm_debug("'%s' matched '%s' for %s", r->id, value, id);
392 unpack_rsc_location(xml_obj, r, NULL, NULL, r->id, nregs,
393 pmatch);
394
395 } else if (invert && (status != 0)) {
396 crm_debug("'%s' is an inverted match of '%s' for %s",
397 r->id, value, id);
398 unpack_rsc_location(xml_obj, r, NULL, NULL, NULL, 0, NULL);
399
400 } else {
401 crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
402 }
403
404 free(pmatch);
405 }
406
407 regfree(&regex);
408 }
409}
410
411// \return Standard Pacemaker return code
412static int
413unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
415{
416 const char *id = NULL;
417 const char *rsc_id = NULL;
418 const char *state = NULL;
419 pcmk_resource_t *rsc = NULL;
420 pcmk_tag_t *tag = NULL;
421 xmlNode *rsc_set = NULL;
422
423 *expanded_xml = NULL;
424
425 CRM_CHECK(xml_obj != NULL, return EINVAL);
426
427 id = pcmk__xe_id(xml_obj);
428 if (id == NULL) {
429 pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID,
430 xml_obj->name);
432 }
433
434 // Check whether there are any resource sets with template or tag references
435 *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, scheduler);
436 if (*expanded_xml != NULL) {
437 crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION);
438 return pcmk_rc_ok;
439 }
440
441 rsc_id = crm_element_value(xml_obj, PCMK_XA_RSC);
442 if (rsc_id == NULL) {
443 return pcmk_rc_ok;
444 }
445
446 if (!pcmk__valid_resource_or_tag(scheduler, rsc_id, &rsc, &tag)) {
447 pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
448 "valid resource or tag", id, rsc_id);
450
451 } else if (rsc != NULL) {
452 // No template is referenced
453 return pcmk_rc_ok;
454 }
455
456 state = crm_element_value(xml_obj, PCMK_XA_ROLE);
457
458 *expanded_xml = pcmk__xml_copy(NULL, xml_obj);
459
460 /* Convert any template or tag reference into constraint
461 * PCMK_XE_RESOURCE_SET
462 */
463 if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, PCMK_XA_RSC,
464 false, scheduler)) {
465 free_xml(*expanded_xml);
466 *expanded_xml = NULL;
468 }
469
470 if (rsc_set != NULL) {
471 if (state != NULL) {
472 /* Move PCMK_XA_RSC_ROLE into converted PCMK_XE_RESOURCE_SET as
473 * PCMK_XA_ROLE attribute
474 */
475 crm_xml_add(rsc_set, PCMK_XA_ROLE, state);
476 pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_ROLE);
477 }
478 crm_log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION);
479
480 } else {
481 // No sets
482 free_xml(*expanded_xml);
483 *expanded_xml = NULL;
484 }
485
486 return pcmk_rc_ok;
487}
488
489// \return Standard Pacemaker return code
490static int
491unpack_location_set(xmlNode *location, xmlNode *set,
493{
494 xmlNode *xml_rsc = NULL;
495 pcmk_resource_t *resource = NULL;
496 const char *set_id;
497 const char *role;
498 const char *local_score;
499
500 CRM_CHECK(set != NULL, return EINVAL);
501
502 set_id = pcmk__xe_id(set);
503 if (set_id == NULL) {
504 pcmk__config_err("Ignoring " PCMK_XE_RESOURCE_SET " without "
505 PCMK_XA_ID " in constraint '%s'",
506 pcmk__s(pcmk__xe_id(location), "(missing ID)"));
508 }
509
510 role = crm_element_value(set, PCMK_XA_ROLE);
511 local_score = crm_element_value(set, PCMK_XA_SCORE);
512
513 for (xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF, NULL, NULL);
514 xml_rsc != NULL; xml_rsc = pcmk__xe_next_same(xml_rsc)) {
515
517 pcmk__xe_id(xml_rsc));
518 if (resource == NULL) {
519 pcmk__config_err("%s: No resource found for %s",
520 set_id, pcmk__xe_id(xml_rsc));
522 }
523
524 unpack_rsc_location(location, resource, role, local_score, NULL, 0,
525 NULL);
526 }
527
528 return pcmk_rc_ok;
529}
530
531void
533{
534 xmlNode *set = NULL;
535 bool any_sets = false;
536
537 xmlNode *orig_xml = NULL;
538 xmlNode *expanded_xml = NULL;
539
540 if (unpack_location_tags(xml_obj, &expanded_xml, scheduler) != pcmk_rc_ok) {
541 return;
542 }
543
544 if (expanded_xml) {
545 orig_xml = xml_obj;
546 xml_obj = expanded_xml;
547 }
548
549 for (set = pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, NULL, NULL);
550 set != NULL; set = pcmk__xe_next_same(set)) {
551
552 any_sets = true;
553 set = expand_idref(set, scheduler->input);
554 if ((set == NULL) // Configuration error, message already logged
555 || (unpack_location_set(xml_obj, set, scheduler) != pcmk_rc_ok)) {
556
557 if (expanded_xml) {
558 free_xml(expanded_xml);
559 }
560 return;
561 }
562 }
563
564 if (expanded_xml) {
565 free_xml(expanded_xml);
566 xml_obj = orig_xml;
567 }
568
569 if (!any_sets) {
570 unpack_simple_location(xml_obj, scheduler);
571 }
572}
573
590 int node_score, const char *discover_mode, pcmk_node_t *node)
591{
592 pcmk__location_t *new_con = NULL;
593
594 CRM_CHECK((node != NULL) || (node_score == 0), return NULL);
595
596 if (id == NULL) {
597 pcmk__config_err("Invalid constraint: no ID specified");
598 return NULL;
599 }
600
601 if (rsc == NULL) {
602 pcmk__config_err("Invalid constraint %s: no resource specified", id);
603 return NULL;
604 }
605
606 new_con = pcmk__assert_alloc(1, sizeof(pcmk__location_t));
607 new_con->id = pcmk__str_copy(id);
608 new_con->rsc = rsc;
609 new_con->nodes = NULL;
611
612 if (pcmk__str_eq(discover_mode, PCMK_VALUE_ALWAYS,
615
616 } else if (pcmk__str_eq(discover_mode, PCMK_VALUE_NEVER,
619
620 } else if (pcmk__str_eq(discover_mode, PCMK_VALUE_EXCLUSIVE,
623 rsc->exclusive_discover = TRUE;
624
625 } else {
626 pcmk__config_err("Invalid " PCMK_XA_RESOURCE_DISCOVERY " value %s "
627 "in location constraint", discover_mode);
628 }
629
630 if (node != NULL) {
631 pcmk_node_t *copy = pe__copy_node(node);
632
633 copy->weight = node_score;
634 new_con->nodes = g_list_prepend(NULL, copy);
635 }
636
637 rsc->cluster->placement_constraints = g_list_prepend(
638 rsc->cluster->placement_constraints, new_con);
639 rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
640
641 return new_con;
642}
643
650void
652{
653 for (GList *iter = scheduler->placement_constraints;
654 iter != NULL; iter = iter->next) {
655 pcmk__location_t *location = iter->data;
656
657 location->rsc->cmds->apply_location(location->rsc, location);
658 }
659}
660
671void
673{
674 bool need_role = false;
675
676 CRM_ASSERT((rsc != NULL) && (location != NULL));
677
678 // If a role was specified, ensure constraint is applicable
679 need_role = (location->role_filter > pcmk_role_unknown);
680 if (need_role && (location->role_filter != rsc->next_role)) {
681 pcmk__rsc_trace(rsc,
682 "Not applying %s to %s because role will be %s not %s",
683 location->id, rsc->id, pcmk_role_text(rsc->next_role),
684 pcmk_role_text(location->role_filter));
685 return;
686 }
687
688 if (location->nodes == NULL) {
689 pcmk__rsc_trace(rsc, "Not applying %s to %s because no nodes match",
690 location->id, rsc->id);
691 return;
692 }
693
694 for (GList *iter = location->nodes; iter != NULL; iter = iter->next) {
695 pcmk_node_t *node = iter->data;
696 pcmk_node_t *allowed_node = g_hash_table_lookup(rsc->allowed_nodes,
697 node->details->id);
698
699 pcmk__rsc_trace(rsc, "Applying %s%s%s to %s score on %s: %c %s",
700 location->id,
701 (need_role? " for role " : ""),
702 (need_role? pcmk_role_text(location->role_filter) : ""),
703 rsc->id, pcmk__node_name(node),
704 ((allowed_node == NULL)? '=' : '+'),
706
707 if (allowed_node == NULL) {
708 allowed_node = pe__copy_node(node);
709 g_hash_table_insert(rsc->allowed_nodes,
710 (gpointer) allowed_node->details->id,
711 allowed_node);
712 } else {
713 allowed_node->weight = pcmk__add_scores(allowed_node->weight,
714 node->weight);
715 }
716
717 if (allowed_node->rsc_discover_mode < location->discover_mode) {
718 if (location->discover_mode == pcmk_probe_exclusive) {
719 rsc->exclusive_discover = TRUE;
720 }
721 /* exclusive > never > always... always is default */
722 allowed_node->rsc_discover_mode = location->discover_mode;
723 }
724 }
725}
const char * pcmk__node_attr(const pcmk_node_t *node, const char *name, const char *target, enum pcmk__rsc_node node_type)
Definition attrs.c:118
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:297
int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
Evaluate a single rule, including all its conditions.
Definition rules.c:1385
pcmk__combine
@ pcmk__combine_or
@ pcmk__combine_unknown
@ pcmk__combine_and
char * pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches)
Definition rules.c:685
enum pcmk__combine pcmk__parse_combine(const char *combine)
Definition rules.c:902
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:484
gboolean local
Definition cpg.c:2
A dumping ground.
@ pcmk__rsc_node_current
Where resource is running.
long long crm_time_get_seconds_since_epoch(const crm_time_t *dt)
Definition iso8601.c:359
void crm_time_free(crm_time_t *dt)
Definition iso8601.c:150
bool crm_time_is_defined(const crm_time_t *t)
Check whether a time object has been initialized yet.
Definition iso8601.c:142
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition iso8601.c:129
struct crm_time_s crm_time_t
Definition iso8601.h:32
G_GNUC_INTERNAL bool pcmk__valid_resource_or_tag(const pcmk_scheduler_t *scheduler, const char *id, pcmk_resource_t **rsc, pcmk_tag_t **tag)
G_GNUC_INTERNAL pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, const pcmk_scheduler_t *scheduler)
#define crm_info(fmt, args...)
Definition logging.h:397
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_log_xml_trace(xml, text)
Definition logging.h:410
#define crm_trace(fmt, args...)
Definition logging.h:402
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
@ pcmk__wo_location_rules
#define pcmk__warn_once(wo_flag, fmt...)
pcmk_scheduler_t * scheduler
@ pcmk_probe_never
Definition nodes.h:56
@ pcmk_probe_always
Definition nodes.h:55
@ pcmk_probe_exclusive
Definition nodes.h:57
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:301
#define PCMK_VALUE_EXCLUSIVE
Definition options.h:150
#define PCMK_META_CONTAINER_ATTRIBUTE_TARGET
Definition options.h:85
#define PCMK_VALUE_AND
Definition options.h:133
#define PCMK_VALUE_OR
Definition options.h:187
#define PCMK_VALUE_NEVER
Definition options.h:177
#define PCMK_VALUE_ALWAYS
Definition options.h:132
pcmk__action_result_t result
Definition pcmk_fence.c:35
const char * target
Definition pcmk_fence.c:29
void pcmk__apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
pcmk__location_t * pcmk__new_location(const char *id, pcmk_resource_t *rsc, int node_score, const char *discover_mode, pcmk_node_t *node)
void pcmk__apply_locations(pcmk_scheduler_t *scheduler)
void pcmk__unpack_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
pcmk_node_t * pe__copy_node(const pcmk_node_t *this_node)
Definition utils.c:89
void pe__update_recheck_time(time_t recheck, pcmk_scheduler_t *scheduler, const char *reason)
Definition utils.c:694
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_ok
Definition results.h:162
@ pcmk_rc_unpack_error
Definition results.h:125
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition roles.c:23
enum rsc_role_e pcmk_parse_role(const char *role)
Parse a resource role from a string role specification.
Definition roles.c:59
rsc_role_e
Definition roles.h:34
@ pcmk_role_started
Started.
Definition roles.h:37
@ pcmk_role_unknown
Resource role is unknown.
Definition roles.h:35
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:38
pcmk_node_t * pcmk_find_node(const pcmk_scheduler_t *scheduler, const char *node_name)
Find a node by name in scheduler data.
Definition scheduler.c:103
#define pcmk__rsc_trace(rsc, fmt, args...)
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition scores.c:86
int char2score(const char *score)
Get the integer value of a score string.
Definition scores.c:36
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:24
int pcmk__add_scores(int score1, int score2)
Definition scores.c:116
Cluster status and scheduling.
@ pcmk__str_null_matches
@ pcmk__str_casei
#define pcmk__str_copy(str)
Location constraint object.
enum pe_discover_e discover_mode
enum rsc_role_e role_filter
pcmk_resource_t * rsc
Data used to evaluate a rule (any NULL items are ignored)
Definition rules.h:57
const regmatch_t * rsc_id_submatches
Resource pattern submatches (as set by regexec()) for rsc_id.
Definition rules.h:99
int rsc_id_nmatches
Number of entries in rsc_id_submatches.
Definition rules.h:102
GHashTable * node_attrs
Operation interval that rule applies to.
Definition rules.h:77
const crm_time_t * now
Current time for rule evaluation purposes.
Definition rules.h:59
const char * rsc_id
Resource ID to compare against a location constraint's resource pattern.
Definition rules.h:96
GHashTable * rsc_params
Definition rules.h:86
int weight
Definition nodes.h:162
int rsc_discover_mode
Definition nodes.h:170
struct pe_node_shared_s * details
Definition nodes.h:167
GHashTable * attrs
Definition nodes.h:142
const char * id
Definition nodes.h:72
pcmk_assignment_methods_t * cmds
Definition resources.h:413
GList * rsc_location
Definition resources.h:443
GHashTable * meta
Definition resources.h:467
pcmk_scheduler_t * cluster
Definition resources.h:408
gboolean exclusive_discover
Definition resources.h:432
GHashTable * allowed_nodes
Definition resources.h:462
enum rsc_role_e next_role
Definition resources.h:465
xmlNode * input
Definition scheduler.h:196
GList * resources
Definition scheduler.h:231
GList * placement_constraints
Definition scheduler.h:232
crm_time_t * now
Definition scheduler.h:198
void(* apply_location)(pcmk_resource_t *rsc, pcmk__location_t *location)
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
Definition xml.c:2152
void free_xml(xmlNode *child)
Definition xml.c:867
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
Definition xml.c:652
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:883
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition xml.c:2108
#define PCMK_XA_SCORE
Definition xml_names.h:391
#define PCMK_XA_SCORE_ATTRIBUTE
Definition xml_names.h:392
#define PCMK_XE_NODE
Definition xml_names.h:133
#define PCMK_XE_RULE
Definition xml_names.h:187
#define PCMK_XE_RESOURCE_REF
Definition xml_names.h:173
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XA_ROLE
Definition xml_names.h:382
#define PCMK_XA_BOOLEAN_OP
Definition xml_names.h:235
#define PCMK_XE_RESOURCE_SET
Definition xml_names.h:174
#define PCMK_XA_RESOURCE_DISCOVERY
Definition xml_names.h:379
#define PCMK_XE_RSC_LOCATION
Definition xml_names.h:184
#define PCMK_XA_RSC_PATTERN
Definition xml_names.h:384
#define PCMK_XA_RSC
Definition xml_names.h:383