19#include <libxml/tree.h>
40 const char *
name = NULL;
81loggable_parent_id(
const xmlNode *xml)
84 const char *parent_id =
"implied";
86 if ((xml != NULL) && (xml->parent != NULL)) {
87 parent_id = pcmk__xe_id(xml->parent);
88 if (parent_id == NULL) {
89 parent_id =
"without ID";
111check_range(
const xmlNode *date_spec,
const char *
id,
const char *attr,
124 "as not passing because '%s' is not a valid range "
129 }
else if ((low != -1) && (value < low)) {
132 }
else if ((high != -1) && (value > high)) {
137 " %s='%s' for %" PRIu32
": %s",
138 id, attr, pcmk__s(range,
""), value,
pcmk_rc_str(rc));
157 const char *
id = NULL;
158 const char *parent_id = loggable_parent_id(date_spec);
177 if ((date_spec == NULL) || (now == NULL)) {
182 id = pcmk__xe_id(date_spec);
183 if (pcmk__str_empty(
id)) {
206 int rc = check_range(date_spec, parent_id, ranges[i].attr,
218#define ADD_COMPONENT(component) do { \
219 int rc = pcmk__add_time_from_xml(*end, component, duration); \
220 if (rc != pcmk_rc_ok) { \
221 pcmk__config_err("Treating " PCMK_XE_DATE_EXPRESSION " %s " \
222 "as not passing because " PCMK_XE_DURATION \
223 " %s attribute %s is invalid: %s", \
225 pcmk__time_component_attr(component), \
227 crm_time_free(*end); \
249 const char *
id = NULL;
250 const char *parent_id = loggable_parent_id(duration);
252 if ((start == NULL) || (duration == NULL)
253 || (end == NULL) || (*end != NULL)) {
258 id = pcmk__xe_id(duration);
259 if (pcmk__str_empty(
id)) {
293evaluate_in_range(
const xmlNode *date_expression,
const char *
id,
314 if ((start == NULL) && (end == NULL)) {
327 if (duration != NULL) {
332 " %s as not passing because duration "
355 if (next_change != NULL) {
380evaluate_gt(
const xmlNode *date_expression,
const char *
id,
426evaluate_lt(
const xmlNode *date_expression,
const char *
id,
473 const char *
id = NULL;
474 const char *op = NULL;
477 if ((date_expression == NULL) || (now == NULL)) {
482 id = pcmk__xe_id(date_expression);
483 if (pcmk__str_empty(
id)) {
492 rc = evaluate_in_range(date_expression,
id, now, next_change);
499 if (date_spec == NULL) {
511 rc = evaluate_gt(date_expression,
id, now, next_change);
514 rc = evaluate_lt(date_expression,
id, now, next_change);
518 " %s as not passing because '%s' is not a valid "
545process_submatches(
const char *
string,
const char *match,
546 const regmatch_t submatches[],
int nmatches,
547 char *expansion,
size_t *nbytes)
549 bool expanded =
false;
550 const char *src = string;
552 if (nbytes != NULL) {
556 while (*src !=
'\0') {
558 size_t match_len = 0;
560 if ((src[0] !=
'%') || !isdigit(src[1])) {
564 if (expansion != NULL) {
567 if (nbytes != NULL) {
574 submatch = src[1] -
'0';
579 if ((nmatches <= submatch)
580 || (submatches[submatch].rm_so < 0)
581 || (submatches[submatch].rm_eo
582 <= submatches[submatch].rm_so)) {
586 match_len = submatches[submatch].rm_eo - submatches[submatch].rm_so;
587 if (nbytes != NULL) {
588 *nbytes += match_len;
590 if (expansion != NULL) {
591 memcpy(expansion, match + submatches[submatch].rm_so,
593 expansion += match_len;
615 const regmatch_t submatches[],
int nmatches)
620 if (pcmk__str_empty(
string) || pcmk__str_empty(match)) {
625 if (!process_submatches(
string, match, submatches, nmatches, NULL,
634 (void) process_submatches(
string, match, submatches, nmatches,
result,
695 const char *value1,
const char *value2)
703 if (((value1 != NULL) && (strchr(value1,
'.') != NULL))
704 || ((value2 != NULL) && (strchr(value2,
'.') != NULL))) {
746 if (value2 == NULL) {
747 return (value1 == NULL)? 0 : 1;
749 if (value1 == NULL) {
755 return strcasecmp(value1, value2);
764 crm_warn(
"Comparing '%s' and '%s' as strings because "
765 "invalid as integers", value1, value2);
766 return strcasecmp(value1, value2);
768 return (integer1 < integer2)? -1 : (integer1 > integer2)? 1 : 0;
780 crm_warn(
"Comparing '%s' and '%s' as strings because invalid as "
781 "numbers", value1, value2);
782 return strcasecmp(value1, value2);
784 return (num1 < num2)? -1 : (num1 > num2)? 1 : 0;
860evaluate_attr_comparison(
const char *actual,
const char *reference,
865 switch (comparison) {
878 switch (comparison) {
889 if ((actual == NULL) || (reference == NULL)) {
893 switch (comparison) {
923 GHashTable *table = NULL;
944 return (
const char *) g_hash_table_lookup(table, value);
961 const char *
id = NULL;
962 const char *op = NULL;
963 const char *attr = NULL;
964 const char *type_s = NULL;
965 const char *value = NULL;
966 const char *actual = NULL;
967 const char *source_s = NULL;
968 const char *reference = NULL;
969 char *expanded_attr = NULL;
976 if ((expression == NULL) || (rule_input == NULL)) {
981 id = pcmk__xe_id(expression);
982 if (pcmk__str_empty(
id)) {
1000 if (expanded_attr != NULL) {
1001 attr = expanded_attr;
1015 "passing because '%s' is not a valid "
1036 switch (comparison) {
1039 if (value != NULL) {
1050 if (value == NULL) {
1058 reference = value_from_source(value, source, rule_input);
1064 actual = g_hash_table_lookup(rule_input->
node_attrs, attr);
1073 "because '%s' is not a valid type",
id, type_s);
1078 rc = evaluate_attr_comparison(actual, reference,
type, comparison);
1079 switch (comparison) {
1088 "%s (attribute %s %s '%s' via %s source as %s type)",
1089 id,
pcmk_rc_str(rc), attr, op, pcmk__s(reference,
""),
1090 pcmk__s(source_s,
"default"), pcmk__s(type_s,
"default"));
1095 free(expanded_attr);
1113 const char *
id = NULL;
1114 const char *standard = NULL;
1115 const char *provider = NULL;
1116 const char *
type = NULL;
1118 if ((rsc_expression == NULL) || (rule_input == NULL)) {
1123 id = pcmk__xe_id(rsc_expression);
1124 if (pcmk__str_empty(
id)) {
1133 if ((standard != NULL)
1136 "actual standard '%s' doesn't match '%s'",
1143 if ((provider != NULL)
1146 "actual provider '%s' doesn't match '%s'",
1156 "actual agent '%s' doesn't match '%s'",
1162 id, pcmk__s(standard,
""),
1163 ((provider == NULL)?
"" :
":"), pcmk__s(provider,
""),
1182 const char *
id = NULL;
1183 const char *
name = NULL;
1184 const char *interval_s = NULL;
1185 guint interval_ms = 0U;
1187 if ((op_expression == NULL) || (rule_input == NULL)) {
1192 id = pcmk__xe_id(op_expression);
1193 if (pcmk__str_empty(
id)) {
1211 "passing because '%s' is not a valid "
1220 "actual name '%s' doesn't match '%s'",
1226 if ((interval_s != NULL) && (interval_ms != rule_input->
op_interval_ms)) {
1228 "actual interval %s doesn't match %s",
1257 if ((condition == NULL) || (rule_input == NULL)) {
1286 "because %s is not a valid condition type",
1287 pcmk__s(pcmk__xe_id(condition),
"without ID"),
1288 (
const char *) condition->name);
1309 const char *
id = NULL;
1310 const char *value = NULL;
1313 if ((rule == NULL) || (rule_input == NULL)) {
1324 id = pcmk__xe_id(rule);
1325 if (pcmk__str_empty(
id)) {
1352 condition != NULL; condition =
pcmk__xe_next(condition, NULL)) {
#define pcmk__assert_alloc(nmemb, size)
@ pcmk__condition_location
@ pcmk__condition_unknown
@ pcmk__condition_attribute
@ pcmk__condition_datetime
@ pcmk__condition_resource
@ pcmk__condition_operation
int compare_version(const char *version1, const char *version2)
enum pcmk_ipc_server type
G_GNUC_INTERNAL void pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source)
@ pcmk__source_meta_attrs
@ pcmk__source_instance_attrs
@ pcmk__comparison_unknown
@ pcmk__comparison_defined
@ pcmk__comparison_undefined
void crm_time_add_seconds(crm_time_t *dt, int value)
Add a given number of seconds to a date/time or duration.
void crm_time_free(crm_time_t *dt)
int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d)
crm_time_t * pcmk_copy_time(const crm_time_t *source)
int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s)
struct crm_time_s crm_time_t
int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d)
int crm_time_compare(const crm_time_t *a, const crm_time_t *b)
int crm_time_get_isoweek(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d)
const char * pcmk__readable_interval(guint interval_ms)
#define crm_warn(fmt, args...)
#define crm_trace(fmt, args...)
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
#define PCMK_VALUE_NOT_DEFINED
#define PCMK_META_INTERVAL
#define PCMK_VALUE_INTEGER
#define PCMK_VALUE_IN_RANGE
#define PCMK_VALUE_DEFINED
#define PCMK_VALUE_NUMBER
#define PCMK_VALUE_DATE_SPEC
#define PCMK_VALUE_LITERAL
#define PCMK_VALUE_VERSION
#define PCMK_VALUE_STRING
pcmk__action_result_t result
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
int pcmk__unpack_duration(const xmlNode *duration, const crm_time_t *start, crm_time_t **end)
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.
#define ADD_COMPONENT(component)
enum pcmk__reference_source pcmk__parse_source(const char *source)
int pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now)
int pcmk__evaluate_date_expression(const xmlNode *date_expression, const crm_time_t *now, crm_time_t *next_change)
enum expression_type pcmk__condition_type(const xmlNode *condition)
enum pcmk__comparison pcmk__parse_comparison(const char *op)
int pcmk__evaluate_attr_expression(const xmlNode *expression, const pcmk_rule_input_t *rule_input)
int pcmk__evaluate_rsc_expression(const xmlNode *rsc_expression, const pcmk_rule_input_t *rule_input)
int pcmk__evaluate_op_expression(const xmlNode *op_expression, const pcmk_rule_input_t *rule_input)
enum pcmk__type pcmk__parse_type(const char *type, enum pcmk__comparison op, const char *value1, const char *value2)
char * pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches)
int pcmk__evaluate_condition(xmlNode *condition, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
enum pcmk__combine pcmk__parse_combine(const char *combine)
int pcmk__cmp_by_type(const char *value1, const char *value2, enum pcmk__type type)
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
int pcmk__xe_get_datetime(const xmlNode *xml, const char *attr, crm_time_t **t)
xmlNode * pcmk__xe_resolve_idref(xmlNode *xml, xmlNode *search)
#define PCMK_XA_VALUE_SOURCE
#define PCMK_XE_EXPRESSION
#define PCMK_XA_OPERATION
#define PCMK_XE_OP_EXPRESSION
#define PCMK_XE_DATE_SPEC
#define PCMK_XA_BOOLEAN_OP
#define PCMK_XE_RSC_EXPRESSION
#define PCMK_XA_ATTRIBUTE
#define PCMK_XA_WEEKYEARS
#define PCMK_XE_OPERATION
#define PCMK_XA_MONTHDAYS
#define PCMK_XE_DATE_EXPRESSION