diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c index 5d876436276..04a53684462 100644 --- a/daemons/controld/controld_control.c +++ b/daemons/controld/controld_control.c @@ -504,7 +504,7 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void crm_time_t *now = crm_time_new(NULL); xmlNode *crmconfig = NULL; xmlNode *alerts = NULL; - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; diff --git a/daemons/controld/controld_remote_proxy.c b/daemons/controld/controld_remote_proxy.c index ff3c0c7e36a..7fa2886fcf2 100644 --- a/daemons/controld/controld_remote_proxy.c +++ b/daemons/controld/controld_remote_proxy.c @@ -29,7 +29,6 @@ #include // pcmk_unpack_nvpair_blocks #include // PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS #include // pcmk_ok, pcmk_rc_*, pcmk_strerror -#include // pcmk_rule_input_t #include // PCMK_XA_*, PCMK_XE_*, etc. #include // crm_system_name #include // lrmd_t @@ -244,7 +243,7 @@ remote_config_check(xmlNode *msg, int call_id, int rc, xmlNode *output, lrmd_t *lrmd = user_data; GHashTable *config_hash = NULL; crm_time_t *now = NULL; - pcmk_rule_input_t rule_input = { NULL, }; + pcmk__rule_input_t rule_input = { NULL, }; if (rc != pcmk_ok) { pcmk__err("Query resulted in an error: %s", pcmk_strerror(rc)); diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am index cf66a79f240..06e6bdf2bdd 100644 --- a/include/crm/common/Makefile.am +++ b/include/crm/common/Makefile.am @@ -39,6 +39,7 @@ header_HEADERS += results.h header_HEADERS += results_compat.h header_HEADERS += roles.h header_HEADERS += rules.h +header_HEADERS += rules_compat.h header_HEADERS += scheduler.h header_HEADERS += scheduler_types.h header_HEADERS += schemas.h diff --git a/include/crm/common/nvpair_compat.h b/include/crm/common/nvpair_compat.h index 829923ea45e..29414a7bf6d 100644 --- a/include/crm/common/nvpair_compat.h +++ b/include/crm/common/nvpair_compat.h @@ -10,11 +10,11 @@ #ifndef PCMK__CRM_COMMON_NVPAIR_COMPAT__H #define PCMK__CRM_COMMON_NVPAIR_COMPAT__H -#include // GHashTable, GSList -#include // xmlNode +#include // GHashTable, GSList +#include // xmlNode -#include // crm_time_t -#include // pcmk_rule_input_t +#include // crm_time_t +#include // pcmk_rule_input_t #ifdef __cplusplus extern "C" { diff --git a/include/crm/common/nvpair_internal.h b/include/crm/common/nvpair_internal.h index b683b3d458a..d1cbe763b73 100644 --- a/include/crm/common/nvpair_internal.h +++ b/include/crm/common/nvpair_internal.h @@ -18,8 +18,8 @@ #include // gboolean, GHashTable #include // xmlNode -#include // pcmk_rule_input_t #include // crm_time_t +#include // pcmk__rule_input_t #include // pcmk__str_eq(), etc. #ifdef __cplusplus @@ -31,7 +31,7 @@ typedef struct { GHashTable *values; // Where to put name/value pairs const char *first_id; // Block with this XML ID should sort first xmlDoc *doc; // XML document to use for resolving IDREFs - pcmk_rule_input_t rule_input; // Data used to evaluate rules + pcmk__rule_input_t rule_input; // Data used to evaluate rules /* Whether each block's values should overwrite any existing ones * @@ -50,7 +50,7 @@ void pcmk__unpack_nvpair_block(void *data, void *user_data); void pcmk__unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, const char *first_id, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *values, crm_time_t *next_change, xmlDoc *doc); diff --git a/include/crm/common/rules.h b/include/crm/common/rules.h index 8bcdbfc6edb..d1263bb6e50 100644 --- a/include/crm/common/rules.h +++ b/include/crm/common/rules.h @@ -10,13 +10,6 @@ #ifndef PCMK__CRM_COMMON_RULES__H #define PCMK__CRM_COMMON_RULES__H -#include // regmatch_t - -#include // GHashTable -#include // xmlNode - -#include // crm_time_t - #ifdef __cplusplus extern "C" { #endif @@ -27,96 +20,12 @@ extern "C" { * \ingroup core */ -/* Allowed subexpressions of a rule - * @COMPAT This should be made internal at an API compatibility break - */ -//!@{ -//! \deprecated For Pacemaker use only -enum expression_type { - pcmk__condition_unknown = 0, // Unknown or invalid condition - pcmk__condition_rule = 1, // Nested rule - pcmk__condition_attribute = 2, // Node attribute expression - pcmk__condition_location = 3, // Node location expression - pcmk__condition_datetime = 5, // Date/time expression - pcmk__condition_resource = 7, // Resource agent expression - pcmk__condition_operation = 8, // Operation expression - -#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) - not_expr = pcmk__condition_unknown, - nested_rule = pcmk__condition_rule, - attr_expr = pcmk__condition_attribute, - loc_expr = pcmk__condition_location, - role_expr = 4, - time_expr = pcmk__condition_datetime, - version_expr = 6, - rsc_expr = pcmk__condition_resource, - op_expr = pcmk__condition_operation, -#endif -}; -//!@} - -/*! - * \brief Data used to evaluate a rule (any \c NULL items are ignored) - * - * \deprecated Use \c pcmk_rule_input_t instead of - * struct pcmk_rule_input. - */ -typedef struct pcmk_rule_input { - // Used to evaluate date expressions - /*! - * Current time for rule evaluation purposes - */ - const crm_time_t *now; - - // Used to evaluate resource type expressions - const char *rsc_standard; //!< Resource standard that rule applies to - const char *rsc_provider; //!< Resource provider that rule applies to - const char *rsc_agent; //!< Resource agent that rule applies to - - // Used to evaluate operation type expressions - const char *op_name; //!< Operation name that rule applies to - unsigned int op_interval_ms; //!< Operation interval that rule applies to - - // Remaining members are used to evaluate node attribute expressions - - /*! - * Node attributes for rule evaluation purposes - * - * \note Though not const, this is used only with g_hash_table_lookup(). - */ - GHashTable *node_attrs; - - // Remaining members are used only within location constraint rules - - /*! - * Resource parameters that can be used as the reference value source - * - * \note Though not const, this is used only with g_hash_table_lookup(). - */ - GHashTable *rsc_params; - - /*! - * Resource meta-attributes that can be used as the reference value source - * - * \note Though not const, this is used only with g_hash_table_lookup(). - */ - GHashTable *rsc_meta; - - //! Resource ID to compare against a location constraint's resource pattern - const char *rsc_id; - - //! Resource pattern submatches (as set by regexec()) for rsc_id - const regmatch_t *rsc_id_submatches; - - //! Number of entries in rsc_id_submatches - int rsc_id_nmatches; -} pcmk_rule_input_t; - -int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, - crm_time_t *next_change); - #ifdef __cplusplus } #endif +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) +#include +#endif + #endif // PCMK__CRM_COMMON_RULES__H diff --git a/include/crm/common/rules_compat.h b/include/crm/common/rules_compat.h new file mode 100644 index 00000000000..3e14b370e12 --- /dev/null +++ b/include/crm/common/rules_compat.h @@ -0,0 +1,74 @@ +/* + * Copyright 2004-2026 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. + */ + +#ifndef PCMK__CRM_COMMON_RULES_COMPAT__H +#define PCMK__CRM_COMMON_RULES_COMPAT__H + +#include // regmatch_t + +#include // GHashTable +#include // xmlNode + +#include // crm_time_t + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file + * \brief Deprecated Pacemaker rules API + * \ingroup core + * \deprecated Do not include this header directly. The nvpair APIs in this + * header, and the header itself, will be removed in a future + * release. + */ + +//!@{ +//! \deprecated Do not use +enum expression_type { + not_expr = 0, + nested_rule = 1, + attr_expr = 2, + loc_expr = 3, + role_expr = 4, + time_expr = 5, + version_expr = 6, + rsc_expr = 7, + op_expr = 8, +}; +//!@} + +//!@{ +//! \deprecated Do not use +typedef struct pcmk_rule_input { + const crm_time_t *now; + const char *rsc_standard; + const char *rsc_provider; + const char *rsc_agent; + const char *op_name; + unsigned int op_interval_ms; + GHashTable *node_attrs; + GHashTable *rsc_params; + GHashTable *rsc_meta; + const char *rsc_id; + const regmatch_t *rsc_id_submatches; + int rsc_id_nmatches; +} pcmk_rule_input_t; +//!@} + +//! \deprecated Do not use +int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, + crm_time_t *next_change); + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_RULES_COMPAT__H diff --git a/include/crm/common/rules_internal.h b/include/crm/common/rules_internal.h index 91ea703febf..f2d74fb7cf6 100644 --- a/include/crm/common/rules_internal.h +++ b/include/crm/common/rules_internal.h @@ -15,9 +15,10 @@ #define PCMK__CRM_COMMON_RULES_INTERNAL__H #include // regmatch_t + +#include // GHashTable #include // xmlNode -#include // enum expression_type, etc. #include // crm_time_t #ifdef __cplusplus @@ -30,7 +31,73 @@ enum pcmk__combine { pcmk__combine_or, }; -enum expression_type pcmk__condition_type(const xmlNode *condition); +/*! + * \internal + * \brief Types of conditions within a rule + */ +enum pcmk__condition { + pcmk__condition_unknown, //!< Unknown or invalid condition + pcmk__condition_rule, //!< Nested rule + pcmk__condition_attribute, //!< Node attribute expression + pcmk__condition_location, //!< Node location expression + pcmk__condition_datetime, //!< Date/time expression + pcmk__condition_resource, //!< Resource agent expression + pcmk__condition_operation, //!< Operation expression +}; + +/*! + * \internal + * \brief Data used to evaluate a rule (any \c NULL items are ignored) + */ +typedef struct { + // Used to evaluate date expressions + const crm_time_t *now; //!< Current time to use for rule evaluation + + // Used to evaluate resource type expressions + const char *rsc_standard; //!< Resource standard that rule applies to + const char *rsc_provider; //!< Resource provider that rule applies to + const char *rsc_agent; //!< Resource agent that rule applies to + + // Used to evaluate operation type expressions + const char *op_name; //!< Operation name that rule applies to + unsigned int op_interval_ms; //!< Operation interval that rule applies to + + // Remaining members are used to evaluate node attribute expressions + + /*! + * Node attributes for rule evaluation purposes + * + * \note Though not const, this is used only with \c g_hash_table_lookup(). + */ + GHashTable *node_attrs; + + // Remaining members are used only within location constraint rules + + /*! + * Resource parameters that can be used as the reference value source + * + * \note Though not const, this is used only with \c g_hash_table_lookup(). + */ + GHashTable *rsc_params; + + /*! + * Resource meta-attributes that can be used as the reference value source + * + * \note Though not const, this is used only with \c g_hash_table_lookup(). + */ + GHashTable *rsc_meta; + + //! Resource ID to compare against a location constraint's resource pattern + const char *rsc_id; + + //! Resource pattern submatches (as set by \c regexec()) for \c rsc_id + const regmatch_t *rsc_id_submatches; + + //! Number of entries in rsc_id_submatches + int rsc_id_nmatches; +} pcmk__rule_input_t; + +enum pcmk__condition pcmk__condition_type(const xmlNode *condition); char *pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches); enum pcmk__combine pcmk__parse_combine(const char *combine); @@ -38,9 +105,19 @@ enum pcmk__combine pcmk__parse_combine(const char *combine); int pcmk__evaluate_date_expression(const xmlNode *date_expression, const crm_time_t *now, crm_time_t *next_change); -int pcmk__evaluate_condition(xmlNode *expr, const pcmk_rule_input_t *rule_input, +int pcmk__evaluate_condition(xmlNode *expr, + const pcmk__rule_input_t *rule_input, crm_time_t *next_change); +int pcmk__evaluate_rule(xmlNode *rule, const pcmk__rule_input_t *rule_input, + crm_time_t *next_change); + +// Redeclare because the definition is in rules_compat.h +typedef struct pcmk_rule_input pcmk_rule_input_t; + +void pcmk__rule_input_convert(const pcmk_rule_input_t *source, + pcmk__rule_input_t *target); + #ifdef __cplusplus } #endif diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h index 908ddd4c766..58d55a22bf2 100644 --- a/include/crm/pengine/internal.h +++ b/include/crm/pengine/internal.h @@ -341,7 +341,7 @@ bool pe__shutdown_requested(const pcmk_node_t *node); void pe__register_messages(pcmk__output_t *out); void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *hash, const char *always_first, pcmk_scheduler_t *scheduler); diff --git a/include/crm/pengine/rules_compat.h b/include/crm/pengine/rules_compat.h index 4112075f33e..036bf0b4d89 100644 --- a/include/crm/pengine/rules_compat.h +++ b/include/crm/pengine/rules_compat.h @@ -30,7 +30,7 @@ extern "C" { */ // @COMPAT sbd's configure script checks for this (as of at least 1.5.2) -//! \deprecated Use pcmk_evaluate_rule() instead +//! \deprecated Do not use gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now); diff --git a/include/pcmki/pcmki_rule.h b/include/pcmki/pcmki_rule.h index dfe8c74e827..805c22eb881 100644 --- a/include/pcmki/pcmki_rule.h +++ b/include/pcmki/pcmki_rule.h @@ -13,9 +13,10 @@ #ifndef PCMK__PCMKI_PCMKI_RULE__H #define PCMK__PCMKI_PCMKI_RULE__H -#include -#include -#include +#include // xmlNode + +#include // pcmk__output_t +#include // crm_time_t #ifdef __cplusplus extern "C" { @@ -24,26 +25,6 @@ extern "C" { int pcmk__check_rules(pcmk__output_t *out, xmlNode *input, const crm_time_t *date_time, const char **rule_ids); -/*! - * \internal - * \brief Check whether a given rule is in effect - * - * \param[in,out] out Output object - * \param[in] input The CIB XML to check (if \c NULL, use current CIB) - * \param[in] date Check whether the rule is in effect at this date and - * time (if \c NULL, use current date and time) - * \param[in] rule_ids The ID of the rule to check - * - * \return Standard Pacemaker return code - */ -static inline int -pcmk__check_rule(pcmk__output_t *out, xmlNode *input, const crm_time_t *date, - const char *rule_id) -{ - const char *rule_ids[] = {rule_id, NULL}; - return pcmk__check_rules(out, input, date, rule_ids); -} - #ifdef __cplusplus } #endif diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index caa017b87d1..5a250ecb89d 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -133,7 +133,7 @@ static void read_config(GHashTable *options, xmlNode *current_cib) { crm_time_t *now = NULL; - pcmk_rule_input_t rule_input = { 0, }; + pcmk__rule_input_t rule_input = { NULL, }; xmlNode *config = pcmk_find_cib_element(current_cib, PCMK_XE_CRM_CONFIG); if (config == NULL) { diff --git a/lib/common/alerts.c b/lib/common/alerts.c index 7facab42f65..dbc4fa3da8f 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -126,7 +126,7 @@ unpack_alert_options(xmlNode *xml, pcmk__alert_t *entry, const char *value = NULL; int rc = pcmk_rc_ok; - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index 685a8043435..91b22e65692 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -28,7 +28,6 @@ #include // crm_time_t #include // mainloop_io_t #include // crm_exit_t -#include // pcmk_rule_input_t #ifdef __cplusplus extern "C" { @@ -453,15 +452,15 @@ int pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now); G_GNUC_INTERNAL int pcmk__evaluate_attr_expression(const xmlNode *expression, - const pcmk_rule_input_t *rule_input); + const pcmk__rule_input_t *rule_input); G_GNUC_INTERNAL int pcmk__evaluate_rsc_expression(const xmlNode *expr, - const pcmk_rule_input_t *rule_input); + const pcmk__rule_input_t *rule_input); G_GNUC_INTERNAL int pcmk__evaluate_op_expression(const xmlNode *expr, - const pcmk_rule_input_t *rule_input); + const pcmk__rule_input_t *rule_input); /* diff --git a/lib/common/nvpair.c b/lib/common/nvpair.c index b855da334b5..c0a49b37509 100644 --- a/lib/common/nvpair.c +++ b/lib/common/nvpair.c @@ -446,8 +446,8 @@ pcmk__unpack_nvpair_block(void *data, void *user_data) rule_xml = pcmk__xe_first_child(pair, PCMK_XE_RULE, NULL, NULL); if ((rule_xml != NULL) - && (pcmk_evaluate_rule(rule_xml, &unpack_data->rule_input, - unpack_data->next_change) != pcmk_rc_ok)) { + && (pcmk__evaluate_rule(rule_xml, &unpack_data->rule_input, + unpack_data->next_change) != pcmk_rc_ok)) { return; } @@ -477,7 +477,7 @@ pcmk__unpack_nvpair_block(void *data, void *user_data) void pcmk__unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, const char *first_id, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *values, crm_time_t *next_change, xmlDoc *doc) { @@ -655,6 +655,7 @@ pcmk__cmp_nvpair_blocks(const void *a, const void *b, void *user_data) // LCOV_EXCL_START #include +#include // pcmk_rule_input_t static int pcmk__compare_nvpair(const void *a, const void *b) @@ -728,11 +729,17 @@ pcmk_unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, const pcmk_rule_input_t *rule_input, GHashTable *values, crm_time_t *next_change) { + pcmk__rule_input_t new_input = { NULL, }; + if (xml == NULL) { return; } - pcmk__unpack_nvpair_blocks(xml, element_name, first_id, rule_input, values, + if (rule_input != NULL) { + pcmk__rule_input_convert(rule_input, &new_input); + } + + pcmk__unpack_nvpair_blocks(xml, element_name, first_id, &new_input, values, next_change, xml->doc); } diff --git a/lib/common/rules.c b/lib/common/rules.c index acb6b88a9f5..03d2e71f020 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -30,7 +30,7 @@ * * \return Condition type corresponding to \p condition */ -enum expression_type +enum pcmk__condition pcmk__condition_type(const xmlNode *condition) { const char *name = NULL; @@ -915,7 +915,7 @@ evaluate_attr_comparison(const char *actual, const char *reference, */ static const char * value_from_source(const char *value, enum pcmk__reference_source source, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { GHashTable *table = NULL; @@ -953,7 +953,7 @@ value_from_source(const char *value, enum pcmk__reference_source source, */ int pcmk__evaluate_attr_expression(const xmlNode *expression, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *id = NULL; const char *op = NULL; @@ -1107,7 +1107,7 @@ pcmk__evaluate_attr_expression(const xmlNode *expression, */ int pcmk__evaluate_rsc_expression(const xmlNode *rsc_expression, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *id = NULL; const char *standard = NULL; @@ -1176,7 +1176,7 @@ pcmk__evaluate_rsc_expression(const xmlNode *rsc_expression, */ int pcmk__evaluate_op_expression(const xmlNode *op_expression, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *id = NULL; const char *name = NULL; @@ -1249,17 +1249,16 @@ pcmk__evaluate_op_expression(const xmlNode *op_expression, */ int pcmk__evaluate_condition(xmlNode *condition, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, crm_time_t *next_change) { - if ((condition == NULL) || (rule_input == NULL)) { return EINVAL; } switch (pcmk__condition_type(condition)) { case pcmk__condition_rule: - return pcmk_evaluate_rule(condition, rule_input, next_change); + return pcmk__evaluate_rule(condition, rule_input, next_change); case pcmk__condition_attribute: case pcmk__condition_location: @@ -1284,12 +1283,13 @@ pcmk__evaluate_condition(xmlNode *condition, pcmk__config_err("Treating rule condition %s as not passing " "because %s is not a valid condition type", pcmk__s(pcmk__xe_id(condition), "without ID"), - (const char *) condition->name); + condition->name); return pcmk_rc_unpack_error; } } /*! + * \internal * \brief Evaluate a single rule, including all its conditions * * \param[in,out] rule XML containing a rule definition or its id-ref @@ -1300,8 +1300,8 @@ pcmk__evaluate_condition(xmlNode *condition, * satisfied, some other value if it is not) */ int -pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, - crm_time_t *next_change) +pcmk__evaluate_rule(xmlNode *rule, const pcmk__rule_input_t *rule_input, + crm_time_t *next_change) { bool empty = true; int rc = pcmk_rc_ok; @@ -1373,3 +1373,49 @@ pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, ((rc == pcmk_rc_ok)? "" : "not ")); return rc; } + +// Deprecated functions kept only for backward API compatibility +// LCOV_EXCL_START + +#include // pcmk_rule_input_t + +void +pcmk__rule_input_convert(const pcmk_rule_input_t *source, + pcmk__rule_input_t *target) +{ + /* @COMPAT Drop this function when pcmk_rule_input_t is dropped. It exists + * purely for as a helper for deprecated API. + */ + pcmk__assert((source != NULL) && (target != NULL)); + + // Non-numeric fields are const and are shared between source and target + target->now = source->now; + target->rsc_standard = source->rsc_standard; + target->rsc_provider = source->rsc_provider; + target->rsc_agent = source->rsc_agent; + target->op_name = source->op_name; + target->op_interval_ms = source->op_interval_ms; + target->node_attrs = source->node_attrs; + target->rsc_params = source->rsc_params; + target->rsc_meta = source->rsc_meta; + target->rsc_id = source->rsc_id; + target->rsc_id_submatches = source->rsc_id_submatches; + target->rsc_id_nmatches = source->rsc_id_nmatches; +} + +int +pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, + crm_time_t *next_change) +{ + pcmk__rule_input_t new_input = { NULL, }; + + if (rule_input == NULL) { + return EINVAL; + } + + pcmk__rule_input_convert(rule_input, &new_input); + return pcmk__evaluate_rule(rule, &new_input, next_change); +} + +// LCOV_EXCL_STOP +// End deprecated API diff --git a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c index aea10f42125..5adb15296e1 100644 --- a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c +++ b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c @@ -65,7 +65,7 @@ null_xml(void **state) GHashTable *values = pcmk__strkey_table(free, free); crm_time_t *now = crm_time_new("2024-01-01 15:00:00"); crm_time_t *next_change = crm_time_new("2024-01-01 20:00:00"); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -84,7 +84,7 @@ null_table(void **state) xmlNode *xml = pcmk__xml_parse(XML_BLOCKS); crm_time_t *now = crm_time_new("2024-01-01 15:00:00"); crm_time_t *next_change = crm_time_new("2024-01-01 20:00:00"); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -105,7 +105,7 @@ rule_passes(void **state) crm_time_t *now = crm_time_new("2024-11-06 15:00:00"); crm_time_t *next_change = crm_time_new("2024-11-06 20:00:00"); GHashTable *values = pcmk__strkey_table(free, free); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -131,7 +131,7 @@ rule_fails(void **state) crm_time_t *next_change = crm_time_new("2024-11-05 20:00:00"); crm_time_t *expected_next_change = crm_time_new("2024-11-05 00:00:01"); GHashTable *values = pcmk__strkey_table(free, free); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -159,7 +159,7 @@ element_name(void **state) xmlNode *xml = pcmk__xml_parse(XML_BLOCKS); crm_time_t *now = crm_time_new("2024-11-06 15:00:00"); GHashTable *values = pcmk__strkey_table(free, free); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; diff --git a/lib/common/tests/rules/Makefile.am b/lib/common/tests/rules/Makefile.am index 57fbd067ba3..343960f35ad 100644 --- a/lib/common/tests/rules/Makefile.am +++ b/lib/common/tests/rules/Makefile.am @@ -19,12 +19,12 @@ check_PROGRAMS += pcmk__evaluate_date_spec_test check_PROGRAMS += pcmk__evaluate_condition_test check_PROGRAMS += pcmk__evaluate_op_expression_test check_PROGRAMS += pcmk__evaluate_rsc_expression_test +check_PROGRAMS += pcmk__evaluate_rule_test check_PROGRAMS += pcmk__parse_combine_test check_PROGRAMS += pcmk__parse_comparison_test check_PROGRAMS += pcmk__parse_source_test check_PROGRAMS += pcmk__parse_type_test check_PROGRAMS += pcmk__replace_submatches_test check_PROGRAMS += pcmk__unpack_duration_test -check_PROGRAMS += pcmk_evaluate_rule_test TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c index b229893aa59..01813dd0d9f 100644 --- a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -10,10 +10,13 @@ #include #include + #include -#include +#include // pcmk__rule_*, pcmk__xml_*, etc. #include +#include // PCMK_XA_*, PCMK_XE_*, etc. + #include "crmcommon_private.h" /* @@ -27,7 +30,7 @@ static const regmatch_t submatches[] = { { .rm_so = 7, .rm_eo = 12 }, // %1 = "north" }; -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { // These are the only members used to evaluate attribute expressions // Used to replace submatches in attribute name diff --git a/lib/common/tests/rules/pcmk__evaluate_condition_test.c b/lib/common/tests/rules/pcmk__evaluate_condition_test.c index 2a09b190596..40965ee32d8 100644 --- a/lib/common/tests/rules/pcmk__evaluate_condition_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_condition_test.c @@ -19,7 +19,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { .rsc_standard = PCMK_RESOURCE_CLASS_OCF, .rsc_provider = "heartbeat", .rsc_agent = "IPaddr2", diff --git a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c index e04497f22f2..40de0f30e00 100644 --- a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -20,7 +20,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { // These are the only members used to evaluate operation expressions .op_name = PCMK_ACTION_MONITOR, .op_interval_ms = 10000, diff --git a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c index e1d24853e5c..025aad58e0b 100644 --- a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -20,7 +20,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { // These are the only members used to evaluate resource expressions .rsc_standard = PCMK_RESOURCE_CLASS_OCF, .rsc_provider = "heartbeat", diff --git a/lib/common/tests/rules/pcmk_evaluate_rule_test.c b/lib/common/tests/rules/pcmk__evaluate_rule_test.c similarity index 87% rename from lib/common/tests/rules/pcmk_evaluate_rule_test.c rename to lib/common/tests/rules/pcmk__evaluate_rule_test.c index 072bbf92c15..96c53fc3266 100644 --- a/lib/common/tests/rules/pcmk_evaluate_rule_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_rule_test.c @@ -19,7 +19,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { .rsc_standard = PCMK_RESOURCE_CLASS_OCF, .rsc_provider = "heartbeat", .rsc_agent = "IPaddr2", @@ -45,14 +45,13 @@ null_invalid(void **state) xmlNode *xml = NULL; crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); - assert_int_equal(pcmk_evaluate_rule(NULL, NULL, next_change), - EINVAL); + assert_int_equal(pcmk__evaluate_rule(NULL, NULL, next_change), EINVAL); xml = pcmk__xml_parse(RULE_OP); - assert_int_equal(pcmk_evaluate_rule(xml, NULL, next_change), EINVAL); + assert_int_equal(pcmk__evaluate_rule(xml, NULL, next_change), EINVAL); pcmk__xml_free(xml); - assert_int_equal(pcmk_evaluate_rule(NULL, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(NULL, &rule_input, next_change), EINVAL); free(next_change); @@ -71,7 +70,7 @@ id_missing(void **state) xmlNode *xml = pcmk__xml_parse(RULE_OP_MISSING_ID); crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, next_change), pcmk_rc_unpack_error); free(next_change); @@ -88,7 +87,7 @@ good_idref(void **state) crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__xe_set(rule_xml, PCMK_XA_ID_REF, "r"); - assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(rule_xml, &rule_input, next_change), pcmk_rc_ok); free(next_change); @@ -103,7 +102,7 @@ bad_idref(void **state) crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__xe_set(rule_xml, PCMK_XA_ID_REF, "x"); - assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(rule_xml, &rule_input, next_change), pcmk_rc_unpack_error); free(next_change); @@ -118,8 +117,7 @@ empty_default(void **state) // Currently acceptable xmlNode *xml = pcmk__xml_parse(RULE_EMPTY); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), - pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -134,8 +132,7 @@ empty_and(void **state) // Currently acceptable xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_AND); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), - pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -149,8 +146,7 @@ empty_or(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_OR); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), - pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -170,7 +166,7 @@ default_boolean_op(void **state) // Defaults to PCMK_VALUE_AND xmlNode *xml = pcmk__xml_parse(RULE_DEFAULT_BOOLEAN_OP); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); @@ -191,7 +187,7 @@ invalid_boolean_op(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_INVALID_BOOLEAN_OP); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_unpack_error); pcmk__xml_free(xml); @@ -212,7 +208,7 @@ and_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_AND_PASSES); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -229,7 +225,7 @@ lonely_and_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_LONELY_AND); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -249,7 +245,7 @@ and_one_fails(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_AND_ONE_FAILS); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); @@ -270,7 +266,7 @@ and_two_fail(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_AND_TWO_FAIL); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); @@ -291,7 +287,7 @@ or_one_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_OR_ONE_PASSES); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -311,7 +307,7 @@ or_two_pass(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_OR_TWO_PASS); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -329,7 +325,7 @@ lonely_or_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_LONELY_OR); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -349,7 +345,7 @@ or_fails(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_OR_FAILS); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); diff --git a/lib/pacemaker/pcmk_sched_constraints.c b/lib/pacemaker/pcmk_sched_constraints.c index ec3c54dadae..759ce545557 100644 --- a/lib/pacemaker/pcmk_sched_constraints.c +++ b/lib/pacemaker/pcmk_sched_constraints.c @@ -243,89 +243,73 @@ pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler) NULL, NULL); set != NULL; set = pcmk__xe_next(set, PCMK_XE_RESOURCE_SET)) { - GList *tag_refs = NULL; - GList *iter = NULL; - - for (xmlNode *xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF, - NULL, NULL); - xml_rsc != NULL; - xml_rsc = pcmk__xe_next(xml_rsc, PCMK_XE_RESOURCE_REF)) { + xmlNode *xml_rsc = pcmk__xe_first_child(set, PCMK_XE_RESOURCE_REF, NULL, + NULL); + xmlNode *next = NULL; + while (xml_rsc != NULL) { pcmk_resource_t *rsc = NULL; pcmk__idref_t *tag = NULL; + xmlNode *last_ref = xml_rsc; + + // xml_rsc may get freed + next = pcmk__xe_next(xml_rsc, PCMK_XE_RESOURCE_REF); if (!pcmk__valid_resource_or_tag(scheduler, pcmk__xe_id(xml_rsc), &rsc, &tag)) { + pcmk__config_err("Ignoring resource sets for constraint '%s' " "because '%s' is not a valid resource or tag", pcmk__xe_id(xml_obj), pcmk__xe_id(xml_rsc)); pcmk__xml_free(new_xml); return NULL; + } - } else if (rsc) { + if (rsc != NULL) { + xml_rsc = next; continue; - - } else if (tag) { - /* PCMK_XE_RESOURCE_REF under PCMK_XE_RESOURCE_SET references - * template or tag - */ - xmlNode *last_ref = xml_rsc; - - /* For example, given the original XML: - * - * - * - * - * - * - * - * If rsc2 and rsc3 are tagged with tag1, we add them after it: - * - * - * - * - * - * - * - * - */ - - for (iter = tag->refs; iter != NULL; iter = iter->next) { - const char *ref_id = iter->data; - xmlNode *new_ref = pcmk__xe_create(set, - PCMK_XE_RESOURCE_REF); - - pcmk__xe_set(new_ref, PCMK_XA_ID, ref_id); - xmlAddNextSibling(last_ref, new_ref); - - last_ref = new_ref; - } - - any_refs = true; - - /* Freeing the resource_ref now would break the XML child - * iteration, so just remember it for freeing later. - */ - tag_refs = g_list_append(tag_refs, xml_rsc); } - } - - /* Now free '', and finally get: - - - - - - + pcmk__assert(tag != NULL); + + /* PCMK_XE_RESOURCE_REF under PCMK_XE_RESOURCE_SET references + * template or tag. + * + * For example, given the original XML: + * + * + * + * + * + * + * + * If rsc2 and rsc3 are tagged with tag1, we add them after it: + * + * + * + * + * + * + * + * + */ + + for (GList *iter = tag->refs; iter != NULL; iter = iter->next) { + const char *ref_id = iter->data; + xmlNode *new_ref = pcmk__xe_create(set, PCMK_XE_RESOURCE_REF); + + pcmk__xe_set(new_ref, PCMK_XA_ID, ref_id); + xmlAddNextSibling(last_ref, new_ref); + + last_ref = new_ref; + } - */ - for (iter = tag_refs; iter != NULL; iter = iter->next) { - xmlNode *tag_ref = iter->data; + any_refs = true; - pcmk__xml_free(tag_ref); + // Drop the tag reference, now that it has been expanded + pcmk__xml_free(xml_rsc); + xml_rsc = next; } - g_list_free(tag_refs); } if (!any_refs) { diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c index 2cb75a9d285..90c780f25f1 100644 --- a/lib/pacemaker/pcmk_sched_location.c +++ b/lib/pacemaker/pcmk_sched_location.c @@ -70,7 +70,7 @@ parse_location_role(const char *role_spec, enum rsc_role_e *role) */ static const char * score_attribute_name(const xmlNode *rule_xml, char **allocated, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *name = NULL; @@ -79,10 +79,10 @@ score_attribute_name(const xmlNode *rule_xml, char **allocated, return NULL; } - /* A score attribute name may use submatches extracted from a - * resource ID regular expression. For example, if score-attribute is - * "loc-\1", rsc-pattern is "ip-(.*)", and the resource ID is "ip-db", then - * the score attribute name is "loc-db". + /* A score attribute name may use submatches extracted from a resource ID + * regular expression. For example, if score-attribute is "loc-%1", + * rsc-pattern is "ip-(.*)", and the resource ID is "ip-db", then the score + * attribute name is "loc-db". */ if ((rule_input->rsc_id != NULL) && (rule_input->rsc_id_nmatches > 0)) { *allocated = pcmk__replace_submatches(name, rule_input->rsc_id, @@ -191,7 +191,8 @@ score_from_attr(const char *constraint_id, const char *attr_name, static bool generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml, const char *discovery, crm_time_t *next_change, - pcmk_rule_input_t *rule_input, const char *constraint_id) + pcmk__rule_input_t *rule_input, + const char *constraint_id) { const char *rule_id = NULL; const char *score_attr = NULL; @@ -269,8 +270,8 @@ generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml, rule_input->rsc_params = pe_rsc_params(rsc, node, rsc->priv->scheduler); - if (pcmk_evaluate_rule(rule_xml, rule_input, - next_change) != pcmk_rc_ok) { + if (pcmk__evaluate_rule(rule_xml, rule_input, + next_change) != pcmk_rc_ok) { continue; } @@ -365,7 +366,7 @@ unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); xmlNode *rule_xml = pcmk__xe_first_child(xml_obj, PCMK_XE_RULE, NULL, NULL); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = rsc->priv->scheduler->priv->now, .rsc_meta = rsc->priv->meta, .rsc_id = rsc_id_match, @@ -395,11 +396,12 @@ unpack_simple_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler) const char *id = pcmk__xe_get(xml_obj, PCMK_XA_ID); const char *value = pcmk__xe_get(xml_obj, PCMK_XA_RSC); - if (value) { - pcmk_resource_t *rsc; + if (value != NULL) { + pcmk_resource_t *rsc = + pcmk__find_constraint_resource(scheduler->priv->resources, value); - rsc = pcmk__find_constraint_resource(scheduler->priv->resources, value); unpack_rsc_location(xml_obj, rsc, NULL, NULL, NULL, 0, NULL); + return; } value = pcmk__xe_get(xml_obj, PCMK_XA_RSC_PATTERN); @@ -472,10 +474,6 @@ unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml, pcmk__idref_t *tag = NULL; xmlNode *rsc_set = NULL; - *expanded_xml = NULL; - - CRM_CHECK(xml_obj != NULL, return EINVAL); - id = pcmk__xe_id(xml_obj); if (id == NULL) { pcmk__config_err("Ignoring <%s> constraint without " PCMK_XA_ID, @@ -499,41 +497,40 @@ unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml, pcmk__config_err("Ignoring constraint '%s' because '%s' is not a " "valid resource or tag", id, rsc_id); return pcmk_rc_unpack_error; + } - } else if (rsc != NULL) { + if (rsc != NULL) { // No template is referenced return pcmk_rc_ok; } - state = pcmk__xe_get(xml_obj, PCMK_XA_ROLE); - *expanded_xml = pcmk__xml_copy(NULL, xml_obj); /* Convert any template or tag reference into constraint * PCMK_XE_RESOURCE_SET */ - if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, PCMK_XA_RSC, - false, scheduler)) { + if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, PCMK_XA_RSC, false, + scheduler)) { g_clear_pointer(expanded_xml, pcmk__xml_free); return pcmk_rc_unpack_error; } - if (rsc_set != NULL) { - if (state != NULL) { - /* Move PCMK_XA_RSC_ROLE into converted PCMK_XE_RESOURCE_SET as - * PCMK_XA_ROLE attribute - */ - pcmk__xe_set(rsc_set, PCMK_XA_ROLE, state); - pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_ROLE); - } - pcmk__log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION); - - } else { - // No sets + if (rsc_set == NULL) { g_clear_pointer(expanded_xml, pcmk__xml_free); + return pcmk_rc_ok; + } + + state = pcmk__xe_get(xml_obj, PCMK_XA_ROLE); + if (state != NULL) { + /* Move PCMK_XA_RSC_ROLE into converted PCMK_XE_RESOURCE_SET as + * PCMK_XA_ROLE attribute + */ + pcmk__xe_set(rsc_set, PCMK_XA_ROLE, state); + pcmk__xe_remove_attr(*expanded_xml, PCMK_XA_ROLE); } + pcmk__log_xml_trace(*expanded_xml, "Expanded " PCMK_XE_RSC_LOCATION); return pcmk_rc_ok; } @@ -583,22 +580,23 @@ unpack_location_set(xmlNode *location, xmlNode *set, void pcmk__unpack_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler) { - xmlNode *set = NULL; bool any_sets = false; - xmlNode *orig_xml = NULL; + xmlNode *orig_xml = xml_obj; xmlNode *expanded_xml = NULL; + CRM_CHECK(xml_obj != NULL, return); + if (unpack_location_tags(xml_obj, &expanded_xml, scheduler) != pcmk_rc_ok) { return; } - if (expanded_xml) { - orig_xml = xml_obj; + if (expanded_xml != NULL) { xml_obj = expanded_xml; } - for (set = pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, NULL, NULL); + for (xmlNode *set = pcmk__xe_first_child(xml_obj, PCMK_XE_RESOURCE_SET, + NULL, NULL); set != NULL; set = pcmk__xe_next(set, PCMK_XE_RESOURCE_SET)) { any_sets = true; @@ -606,21 +604,18 @@ pcmk__unpack_location(xmlNode *xml_obj, pcmk_scheduler_t *scheduler) if ((set == NULL) // Configuration error, message already logged || (unpack_location_set(xml_obj, set, scheduler) != pcmk_rc_ok)) { - if (expanded_xml) { - pcmk__xml_free(expanded_xml); - } + pcmk__xml_free(expanded_xml); return; } } - if (expanded_xml) { - pcmk__xml_free(expanded_xml); - xml_obj = orig_xml; - } + pcmk__xml_free(expanded_xml); - if (!any_sets) { - unpack_simple_location(xml_obj, scheduler); + if (any_sets) { + return; } + + unpack_simple_location(orig_xml, scheduler); } /*! diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c index e2ce92c405c..3b967291f6c 100644 --- a/lib/pengine/complex.c +++ b/lib/pengine/complex.c @@ -148,7 +148,7 @@ dup_attr(void *key, void *value, void *user_data) static void expand_parents_fixed_nvpairs(const pcmk_resource_t *rsc, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *meta_hash, pcmk_scheduler_t *scheduler) { GHashTable *parent_orig_meta = pcmk__strkey_table(free, free); @@ -209,7 +209,7 @@ void get_meta_attributes(GHashTable *meta_hash, const pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_scheduler_t *scheduler) { - pcmk_rule_input_t rule_input = { NULL, }; + pcmk__rule_input_t rule_input = { NULL, }; CRM_CHECK((meta_hash != NULL) && (rsc != NULL) && (scheduler != NULL), return); @@ -260,7 +260,7 @@ void get_rsc_attributes(GHashTable *instance_attrs, const pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler) { - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = NULL, }; @@ -714,7 +714,7 @@ pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, bool remote_node = false; pcmk__resource_private_t *rsc_private = NULL; - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = NULL, }; diff --git a/lib/pengine/pe_actions.c b/lib/pengine/pe_actions.c index c0303eb3785..473404b6a7e 100644 --- a/lib/pengine/pe_actions.c +++ b/lib/pengine/pe_actions.c @@ -270,7 +270,7 @@ pcmk__unpack_action_rsc_params(const xmlNode *action_xml, { GHashTable *params = pcmk__strkey_table(free, free); - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, .node_attrs = node_attrs, }; @@ -706,7 +706,7 @@ pcmk__unpack_action_meta(pcmk_resource_t *rsc, const pcmk_node_t *node, const char *timeout_spec = NULL; const char *str = NULL; - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { /* Node attributes are not set because node expressions are not allowed * for meta-attributes */ diff --git a/lib/pengine/rules_compat.c b/lib/pengine/rules_compat.c index 434f78c1dde..02057759eba 100644 --- a/lib/pengine/rules_compat.c +++ b/lib/pengine/rules_compat.c @@ -14,27 +14,27 @@ #include // xmlNode #include +#include // pcmk__evaluate_rule, etc. #include // crm_time_t #include // enum rsc_role_e - #include -#include // pcmk_rule_input_t, etc. // Deprecated functions kept only for backward API compatibility // LCOV_EXCL_START +#include // pcmk_rule_input_t #include #include gboolean test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now) { - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .node_attrs = node_hash, .now = now, }; - return pcmk_evaluate_rule(rule, &rule_input, NULL) == pcmk_rc_ok; + return pcmk__evaluate_rule(rule, &rule_input, NULL) == pcmk_rc_ok; } /*! @@ -79,6 +79,7 @@ pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, crm_time_t *next_change) { GList *pairs = NULL; + pcmk_rule_input_t tmp_input = { NULL, }; pcmk__nvpair_unpack_t data = { .values = hash, .first_id = always_first, @@ -96,7 +97,11 @@ pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, } data.doc = xml_obj->doc; - map_rule_input(&data.rule_input, rule_data); + + map_rule_input(&tmp_input, rule_data); + if (rule_data != NULL) { + pcmk__rule_input_convert(&tmp_input, &data.rule_input); + } pairs = g_list_sort_with_data(pairs, pcmk__cmp_nvpair_blocks, &data); g_list_foreach(pairs, pcmk__unpack_nvpair_block, &data); diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c index 3b2744d2edc..e8106cf7641 100644 --- a/lib/pengine/unpack.c +++ b/lib/pengine/unpack.c @@ -239,7 +239,7 @@ unpack_config(xmlNode *config, pcmk_scheduler_t *scheduler) const char *value = NULL; GHashTable *config_hash = pcmk__strkey_table(free, free); - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, }; @@ -4991,7 +4991,7 @@ add_node_attrs(const xmlNode *xml_obj, pcmk_node_t *node, bool overwrite, { const char *cluster_name = NULL; const char *dc_id = pcmk__xe_get(scheduler->input, PCMK_XA_DC_UUID); - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, }; diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 49003b56909..c694ed2d0da 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -702,7 +702,7 @@ pe__shutdown_requested(const pcmk_node_t *node) */ void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *hash, const char *always_first, pcmk_scheduler_t *scheduler) { diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 8c2d165b19d..cd9ea4d8c69 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -1455,7 +1455,7 @@ handle_get_param(pcmk_resource_t *rsc, pcmk_node_t *node, cib_t *cib_conn, value = pcmk__xe_get(rsc->priv->xml, options.prop_name); } else { - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, };