Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F7989065
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
index 7461f6d78c..1e0436406a 100644
--- a/lib/pengine/rules.c
+++ b/lib/pengine/rules.c
@@ -1,316 +1,319 @@
/*
* Copyright 2004-2024 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.
*/
#include <crm_internal.h>
#include <glib.h>
#include <crm/crm.h>
#include <crm/common/xml.h>
#include <crm/pengine/rules.h>
#include <crm/common/iso8601_internal.h>
#include <crm/common/nvpair_internal.h>
#include <crm/common/rules_internal.h>
#include <crm/common/xml_internal.h>
#include <crm/pengine/internal.h>
#include <crm/pengine/rules_internal.h>
#include <sys/types.h>
#include <regex.h>
CRM_TRACE_INIT_DATA(pe_rules);
/*!
* \internal
* \brief Map pe_rule_eval_data_t to pcmk_rule_input_t
*
* \param[out] new New data struct
* \param[in] old Old data struct
*/
static void
map_rule_input(pcmk_rule_input_t *new, const pe_rule_eval_data_t *old)
{
if (old == NULL) {
return;
}
new->now = old->now;
new->node_attrs = old->node_hash;
if (old->rsc_data != NULL) {
new->rsc_standard = old->rsc_data->standard;
new->rsc_provider = old->rsc_data->provider;
new->rsc_agent = old->rsc_data->agent;
}
if (old->match_data != NULL) {
new->rsc_params = old->match_data->params;
new->rsc_meta = old->match_data->meta;
if (old->match_data->re != NULL) {
new->rsc_id = old->match_data->re->string;
new->rsc_id_submatches = old->match_data->re->pmatch;
new->rsc_id_nmatches = old->match_data->re->nregs;
}
}
if (old->op_data != NULL) {
new->op_name = old->op_data->op_name;
new->op_interval_ms = old->op_data->interval;
}
}
static gint
sort_pairs(gconstpointer a, gconstpointer b, gpointer user_data)
{
const xmlNode *pair_a = a;
const xmlNode *pair_b = b;
pcmk__nvpair_unpack_t *unpack_data = user_data;
const char *score = NULL;
int score_a = 0;
int score_b = 0;
if (a == NULL && b == NULL) {
return 0;
} else if (a == NULL) {
return 1;
} else if (b == NULL) {
return -1;
}
if (pcmk__str_eq(pcmk__xe_id(pair_a), unpack_data->first_id,
pcmk__str_none)) {
return -1;
} else if (pcmk__str_eq(pcmk__xe_id(pair_b), unpack_data->first_id,
pcmk__str_none)) {
return 1;
}
score = crm_element_value(pair_a, PCMK_XA_SCORE);
score_a = char2score(score);
score = crm_element_value(pair_b, PCMK_XA_SCORE);
score_b = char2score(score);
/* If we're overwriting values, we want lowest score first, so the highest
* score is processed last; if we're not overwriting values, we want highest
* score first, so nothing else overwrites it.
*/
if (score_a < score_b) {
return unpack_data->overwrite? -1 : 1;
} else if (score_a > score_b) {
return unpack_data->overwrite? 1 : -1;
}
return 0;
}
static void
populate_hash(xmlNode *nvpair_list, GHashTable *hash, bool overwrite)
{
if (pcmk__xe_is(nvpair_list->children, PCMK__XE_ATTRIBUTES)) {
nvpair_list = nvpair_list->children;
}
for (xmlNode *nvpair = pcmk__xe_first_child(nvpair_list, PCMK_XE_NVPAIR,
NULL, NULL);
nvpair != NULL; nvpair = pcmk__xe_next_same(nvpair)) {
xmlNode *ref_nvpair = pcmk__xe_resolve_idref(nvpair, NULL);
const char *name = NULL;
const char *value = NULL;
const char *old_value = NULL;
if (ref_nvpair == NULL) {
/* Not possible with schema validation enabled (error already
* logged)
*/
continue;
}
name = crm_element_value(nvpair, PCMK_XA_NAME);
if (name == NULL) {
/* @TODO Always get name from ref_nvpair. Currently an nvpair with
* an id-ref is allowed to have a name, which overrides the name in
* the referenced nvpair.
*
* This feature was added by commit 3912538 but is undocumented and
* inconsistently implemented. The code often ignores name if there
* is an id-ref, or in some places assumes that id and value exist
* if name exists.
*
* Disallow this in the schema first, and then update this function.
*/
name = crm_element_value(ref_nvpair, PCMK_XA_NAME);
}
value = crm_element_value(ref_nvpair, PCMK_XA_VALUE);
if ((name == NULL) || (value == NULL)) {
continue;
}
old_value = g_hash_table_lookup(hash, name);
if (pcmk__str_eq(value, "#default", pcmk__str_casei)) {
// @COMPAT Deprecated since 2.1.8
pcmk__config_warn("Support for setting meta-attributes (such as "
"%s) to the explicit value '#default' is "
"deprecated and will be removed in a future "
"release", name);
if (old_value != NULL) {
crm_trace("Letting %s default (removing explicit value \"%s\")",
name, value);
g_hash_table_remove(hash, name);
}
} else if (old_value == NULL) {
crm_trace("Setting %s=\"%s\"", name, value);
pcmk__insert_dup(hash, name, value);
} else if (overwrite) {
crm_trace("Setting %s=\"%s\" (overwriting old value \"%s\")",
name, value, old_value);
pcmk__insert_dup(hash, name, value);
}
}
}
static void
unpack_attr_set(gpointer data, gpointer user_data)
{
xmlNode *pair = data;
pcmk__nvpair_unpack_t *unpack_data = user_data;
- if (pcmk__evaluate_rules(pair, &(unpack_data->rule_input),
- unpack_data->next_change) != pcmk_rc_ok) {
+ xmlNode *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)) {
return;
}
crm_trace("Adding name/value pairs from %s %s overwrite",
pcmk__xe_id(pair), (unpack_data->overwrite? "with" : "without"));
populate_hash(pair, unpack_data->values, unpack_data->overwrite);
}
/*!
* \internal
* \brief Create a sorted list of nvpair blocks
*
* \param[in] xml_obj XML element containing blocks of nvpair elements
* \param[in] set_name If not NULL, only get blocks of this element
*
* \return List of XML blocks of name/value pairs
*/
static GList *
make_pairs(const xmlNode *xml_obj, const char *set_name)
{
GList *unsorted = NULL;
if (xml_obj == NULL) {
return NULL;
}
for (xmlNode *attr_set = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
attr_set != NULL; attr_set = pcmk__xe_next(attr_set)) {
if ((set_name == NULL) || pcmk__xe_is(attr_set, set_name)) {
xmlNode *expanded_attr_set = pcmk__xe_resolve_idref(attr_set, NULL);
if (expanded_attr_set == NULL) {
continue; // Not possible with schema validation enabled
}
unsorted = g_list_prepend(unsorted, expanded_attr_set);
}
}
return unsorted;
}
/*!
* \brief Extract nvpair blocks contained by an XML element into a hash table
*
* \param[in,out] top Ignored
* \param[in] xml_obj XML element containing blocks of nvpair elements
* \param[in] set_name If not NULL, only use blocks of this element
* \param[in] rule_data Matching parameters to use when unpacking
* \param[out] hash Where to store extracted name/value pairs
* \param[in] always_first If not NULL, process block with this ID first
* \param[in] overwrite Whether to replace existing values with same
* name (all internal callers pass \c FALSE)
* \param[out] next_change If not NULL, set to when evaluation will change
*/
void
pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
const pe_rule_eval_data_t *rule_data, GHashTable *hash,
const char *always_first, gboolean overwrite,
crm_time_t *next_change)
{
GList *pairs = make_pairs(xml_obj, set_name);
if (pairs) {
pcmk__nvpair_unpack_t data = {
.values = hash,
.first_id = always_first,
.overwrite = overwrite,
.next_change = next_change,
};
map_rule_input(&(data.rule_input), rule_data);
pairs = g_list_sort_with_data(pairs, sort_pairs, &data);
g_list_foreach(pairs, unpack_attr_set, &data);
g_list_free(pairs);
}
}
/*!
* \brief Extract nvpair blocks contained by an XML element into a hash table
*
* \param[in,out] top Ignored
* \param[in] xml_obj XML element containing blocks of nvpair elements
* \param[in] set_name Element name to identify nvpair blocks
* \param[in] node_hash Node attributes to use when evaluating rules
* \param[out] hash Where to store extracted name/value pairs
* \param[in] always_first If not NULL, process block with this ID first
* \param[in] overwrite Whether to replace existing values with same
* name (all internal callers pass \c FALSE)
* \param[in] now Time to use when evaluating rules
* \param[out] next_change If not NULL, set to when evaluation will change
*/
void
pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name,
GHashTable *node_hash, GHashTable *hash,
const char *always_first, gboolean overwrite,
crm_time_t *now, crm_time_t *next_change)
{
pe_rule_eval_data_t rule_data = {
.node_hash = node_hash,
.now = now,
.match_data = NULL,
.rsc_data = NULL,
.op_data = NULL
};
pe_eval_nvpairs(NULL, xml_obj, set_name, &rule_data, hash,
always_first, overwrite, next_change);
}
// Deprecated functions kept only for backward API compatibility
// LCOV_EXCL_START
#include <crm/pengine/rules_compat.h>
gboolean
test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now)
{
pcmk_rule_input_t rule_input = {
.node_attrs = node_hash,
.now = now,
};
return pcmk_evaluate_rule(rule, &rule_input, NULL) == pcmk_rc_ok;
}
// LCOV_EXCL_STOP
// End deprecated API
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Oct 25, 2:13 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2609934
Default Alt Text
(10 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment