From 2f10dde2f2a0ac7a3d74cb2f398be1deaba75615 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 6 Apr 2020 11:22:50 -0400 Subject: [PATCH 01/17] Feature: scheduler: Add new expression_type values. --- include/crm/pengine/rules.h | 4 +++- lib/pengine/rules.c | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/crm/pengine/rules.h b/include/crm/pengine/rules.h index ebd3148..37f092b 100644 --- a/include/crm/pengine/rules.h +++ b/include/crm/pengine/rules.h @@ -28,7 +28,9 @@ enum expression_type { loc_expr, role_expr, time_expr, - version_expr + version_expr, + rsc_expr, + op_expr }; typedef struct pe_re_match_data { diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index fa9a222..130bada 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -189,6 +189,12 @@ find_expression_type(xmlNode * expr) if (safe_str_eq(tag, "date_expression")) { return time_expr; + } else if (safe_str_eq(tag, "rsc_expression")) { + return rsc_expr; + + } else if (safe_str_eq(tag, "op_expression")) { + return op_expr; + } else if (safe_str_eq(tag, XML_TAG_RULE)) { return nested_rule; -- 1.8.3.1 From bc7491e5226af2a2e7f1a9b2d61892d3af0767fe Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 3 Apr 2020 15:03:23 -0400 Subject: [PATCH 02/17] Refactor: scheduler: Add new pe__eval_*_expr functions. These new functions all take the same input arguments - an xmlNodePtr and a pe_rule_eval_data_t. This latter type holds all the parameters that could possibly be useful for evaluating some rule. Most functions will only need a few items out of this structure. Then, implement pe_test_*_expression in terms of these new functions. --- include/crm/pengine/common.h | 37 ++- include/crm/pengine/rules.h | 13 - include/crm/pengine/rules_internal.h | 5 + lib/pengine/rules.c | 592 +++++++++++++++++++---------------- 4 files changed, 363 insertions(+), 284 deletions(-) diff --git a/include/crm/pengine/common.h b/include/crm/pengine/common.h index 48c2b66..3a770b7 100644 --- a/include/crm/pengine/common.h +++ b/include/crm/pengine/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2019 the Pacemaker project contributors + * Copyright 2004-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -15,6 +15,9 @@ extern "C" { #endif # include +# include + +# include extern gboolean was_processing_error; extern gboolean was_processing_warning; @@ -131,6 +134,38 @@ recovery2text(enum rsc_recovery_type type) return "Unknown"; } +typedef struct pe_re_match_data { + char *string; + int nregs; + regmatch_t *pmatch; +} pe_re_match_data_t; + +typedef struct pe_match_data { + pe_re_match_data_t *re; + GHashTable *params; + GHashTable *meta; +} pe_match_data_t; + +typedef struct pe_rsc_eval_data { + const char *standard; + const char *provider; + const char *agent; +} pe_rsc_eval_data_t; + +typedef struct pe_op_eval_data { + const char *op_name; + guint interval; +} pe_op_eval_data_t; + +typedef struct pe_rule_eval_data { + GHashTable *node_hash; + enum rsc_role_e role; + crm_time_t *now; + pe_match_data_t *match_data; + pe_rsc_eval_data_t *rsc_data; + pe_op_eval_data_t *op_data; +} pe_rule_eval_data_t; + #ifdef __cplusplus } #endif diff --git a/include/crm/pengine/rules.h b/include/crm/pengine/rules.h index 37f092b..d7bdbf9 100644 --- a/include/crm/pengine/rules.h +++ b/include/crm/pengine/rules.h @@ -15,7 +15,6 @@ extern "C" { #endif # include -# include # include # include @@ -33,18 +32,6 @@ enum expression_type { op_expr }; -typedef struct pe_re_match_data { - char *string; - int nregs; - regmatch_t *pmatch; -} pe_re_match_data_t; - -typedef struct pe_match_data { - pe_re_match_data_t *re; - GHashTable *params; - GHashTable *meta; -} pe_match_data_t; - enum expression_type find_expression_type(xmlNode * expr); gboolean pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, diff --git a/include/crm/pengine/rules_internal.h b/include/crm/pengine/rules_internal.h index fd65c1e..8a22108 100644 --- a/include/crm/pengine/rules_internal.h +++ b/include/crm/pengine/rules_internal.h @@ -21,6 +21,11 @@ void pe_free_alert_list(GListPtr alert_list); crm_time_t *pe_parse_xml_duration(crm_time_t * start, xmlNode * duration_spec); +gboolean pe__eval_attr_expr(xmlNode *expr, pe_rule_eval_data_t *rule_data); +int pe__eval_date_expr(xmlNode *expr, pe_rule_eval_data_t *rule_data, + crm_time_t *next_change); +gboolean pe__eval_role_expr(xmlNode *expr, pe_rule_eval_data_t *rule_data); + int pe_eval_date_expression(xmlNode *time_expr, crm_time_t *now, crm_time_t *next_change); diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index 130bada..3f316c2 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -219,201 +219,34 @@ find_expression_type(xmlNode * expr) } gboolean -pe_test_role_expression(xmlNode * expr, enum rsc_role_e role, crm_time_t * now) +pe_test_role_expression(xmlNode *expr, enum rsc_role_e role, crm_time_t *now) { - gboolean accept = FALSE; - const char *op = NULL; - const char *value = NULL; - - if (role == RSC_ROLE_UNKNOWN) { - return accept; - } - - value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); - op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); - - if (safe_str_eq(op, "defined")) { - if (role > RSC_ROLE_STARTED) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "not_defined")) { - if (role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "eq")) { - if (text2role(value) == role) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "ne")) { - // Test "ne" only with promotable clone roles - if (role < RSC_ROLE_SLAVE && role > RSC_ROLE_UNKNOWN) { - accept = FALSE; - - } else if (text2role(value) != role) { - accept = TRUE; - } - } - return accept; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = role, + .now = now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + + return pe__eval_role_expr(expr, &rule_data); } gboolean pe_test_attr_expression(xmlNode *expr, GHashTable *hash, crm_time_t *now, pe_match_data_t *match_data) { - gboolean accept = FALSE; - gboolean attr_allocated = FALSE; - int cmp = 0; - const char *h_val = NULL; - GHashTable *table = NULL; - - const char *op = NULL; - const char *type = NULL; - const char *attr = NULL; - const char *value = NULL; - const char *value_source = NULL; - - attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); - op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); - value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); - type = crm_element_value(expr, XML_EXPR_ATTR_TYPE); - value_source = crm_element_value(expr, XML_EXPR_ATTR_VALUE_SOURCE); - - if (attr == NULL || op == NULL) { - pe_err("Invalid attribute or operation in expression" - " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value)); - return FALSE; - } - - if (match_data) { - if (match_data->re) { - char *resolved_attr = pe_expand_re_matches(attr, match_data->re); - - if (resolved_attr) { - attr = (const char *) resolved_attr; - attr_allocated = TRUE; - } - } - - if (safe_str_eq(value_source, "param")) { - table = match_data->params; - } else if (safe_str_eq(value_source, "meta")) { - table = match_data->meta; - } - } - - if (table) { - const char *param_name = value; - const char *param_value = NULL; - - if (param_name && param_name[0]) { - if ((param_value = (const char *)g_hash_table_lookup(table, param_name))) { - value = param_value; - } - } - } - - if (hash != NULL) { - h_val = (const char *)g_hash_table_lookup(hash, attr); - } - - if (attr_allocated) { - free((char *)attr); - attr = NULL; - } - - if (value != NULL && h_val != NULL) { - if (type == NULL) { - if (safe_str_eq(op, "lt") - || safe_str_eq(op, "lte") - || safe_str_eq(op, "gt") - || safe_str_eq(op, "gte")) { - type = "number"; - - } else { - type = "string"; - } - crm_trace("Defaulting to %s based comparison for '%s' op", type, op); - } - - if (safe_str_eq(type, "string")) { - cmp = strcasecmp(h_val, value); - - } else if (safe_str_eq(type, "number")) { - int h_val_f = crm_parse_int(h_val, NULL); - int value_f = crm_parse_int(value, NULL); - - if (h_val_f < value_f) { - cmp = -1; - } else if (h_val_f > value_f) { - cmp = 1; - } else { - cmp = 0; - } - - } else if (safe_str_eq(type, "version")) { - cmp = compare_version(h_val, value); - - } - - } else if (value == NULL && h_val == NULL) { - cmp = 0; - } else if (value == NULL) { - cmp = 1; - } else { - cmp = -1; - } - - if (safe_str_eq(op, "defined")) { - if (h_val != NULL) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "not_defined")) { - if (h_val == NULL) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "eq")) { - if ((h_val == value) || cmp == 0) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "ne")) { - if ((h_val == NULL && value != NULL) - || (h_val != NULL && value == NULL) - || cmp != 0) { - accept = TRUE; - } - - } else if (value == NULL || h_val == NULL) { - // The comparison is meaningless from this point on - accept = FALSE; - - } else if (safe_str_eq(op, "lt")) { - if (cmp < 0) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "lte")) { - if (cmp <= 0) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "gt")) { - if (cmp > 0) { - accept = TRUE; - } - - } else if (safe_str_eq(op, "gte")) { - if (cmp >= 0) { - accept = TRUE; - } - } - - return accept; + pe_rule_eval_data_t rule_data = { + .node_hash = hash, + .role = RSC_ROLE_UNKNOWN, + .now = now, + .match_data = match_data, + .rsc_data = NULL, + .op_data = NULL + }; + + return pe__eval_attr_expr(expr, &rule_data); } /* As per the nethack rules: @@ -587,10 +420,18 @@ pe_parse_xml_duration(crm_time_t * start, xmlNode * duration_spec) * \return TRUE if date expression is in effect at given time, FALSE otherwise */ gboolean -pe_test_date_expression(xmlNode *time_expr, crm_time_t *now, - crm_time_t *next_change) +pe_test_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change) { - switch (pe_eval_date_expression(time_expr, now, next_change)) { + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + + switch (pe__eval_date_expr(expr, &rule_data, next_change)) { case pcmk_rc_within_range: case pcmk_rc_ok: return TRUE; @@ -623,86 +464,18 @@ crm_time_set_if_earlier(crm_time_t *next_change, crm_time_t *t) * \return Standard Pacemaker return code */ int -pe_eval_date_expression(xmlNode *time_expr, crm_time_t *now, - crm_time_t *next_change) +pe_eval_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change) { - crm_time_t *start = NULL; - crm_time_t *end = NULL; - const char *value = NULL; - const char *op = crm_element_value(time_expr, "operation"); - - xmlNode *duration_spec = NULL; - xmlNode *date_spec = NULL; - - // "undetermined" will also be returned for parsing errors - int rc = pcmk_rc_undetermined; - - crm_trace("Testing expression: %s", ID(time_expr)); - - duration_spec = first_named_child(time_expr, "duration"); - date_spec = first_named_child(time_expr, "date_spec"); - - value = crm_element_value(time_expr, "start"); - if (value != NULL) { - start = crm_time_new(value); - } - value = crm_element_value(time_expr, "end"); - if (value != NULL) { - end = crm_time_new(value); - } - - if (start != NULL && end == NULL && duration_spec != NULL) { - end = pe_parse_xml_duration(start, duration_spec); - } - - if ((op == NULL) || safe_str_eq(op, "in_range")) { - if ((start == NULL) && (end == NULL)) { - // in_range requires at least one of start or end - } else if ((start != NULL) && (crm_time_compare(now, start) < 0)) { - rc = pcmk_rc_before_range; - crm_time_set_if_earlier(next_change, start); - } else if ((end != NULL) && (crm_time_compare(now, end) > 0)) { - rc = pcmk_rc_after_range; - } else { - rc = pcmk_rc_within_range; - if (end && next_change) { - // Evaluation doesn't change until second after end - crm_time_add_seconds(end, 1); - crm_time_set_if_earlier(next_change, end); - } - } - - } else if (safe_str_eq(op, "date_spec")) { - rc = pe_cron_range_satisfied(now, date_spec); - // @TODO set next_change appropriately - - } else if (safe_str_eq(op, "gt")) { - if (start == NULL) { - // gt requires start - } else if (crm_time_compare(now, start) > 0) { - rc = pcmk_rc_within_range; - } else { - rc = pcmk_rc_before_range; - - // Evaluation doesn't change until second after start - crm_time_add_seconds(start, 1); - crm_time_set_if_earlier(next_change, start); - } - - } else if (safe_str_eq(op, "lt")) { - if (end == NULL) { - // lt requires end - } else if (crm_time_compare(now, end) < 0) { - rc = pcmk_rc_within_range; - crm_time_set_if_earlier(next_change, end); - } else { - rc = pcmk_rc_after_range; - } - } - - crm_time_free(start); - crm_time_free(end); - return rc; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + + return pe__eval_date_expr(expr, &rule_data, next_change); } // Information about a block of nvpair elements @@ -1111,6 +884,285 @@ pe_unpack_versioned_parameters(xmlNode *versioned_params, const char *ra_version } #endif +gboolean +pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) +{ + gboolean accept = FALSE; + gboolean attr_allocated = FALSE; + int cmp = 0; + const char *h_val = NULL; + GHashTable *table = NULL; + + const char *op = NULL; + const char *type = NULL; + const char *attr = NULL; + const char *value = NULL; + const char *value_source = NULL; + + attr = crm_element_value(expr, XML_EXPR_ATTR_ATTRIBUTE); + op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); + value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); + type = crm_element_value(expr, XML_EXPR_ATTR_TYPE); + value_source = crm_element_value(expr, XML_EXPR_ATTR_VALUE_SOURCE); + + if (attr == NULL || op == NULL) { + pe_err("Invalid attribute or operation in expression" + " (\'%s\' \'%s\' \'%s\')", crm_str(attr), crm_str(op), crm_str(value)); + return FALSE; + } + + if (rule_data->match_data) { + if (rule_data->match_data->re) { + char *resolved_attr = pe_expand_re_matches(attr, rule_data->match_data->re); + + if (resolved_attr) { + attr = (const char *) resolved_attr; + attr_allocated = TRUE; + } + } + + if (safe_str_eq(value_source, "param")) { + table = rule_data->match_data->params; + } else if (safe_str_eq(value_source, "meta")) { + table = rule_data->match_data->meta; + } + } + + if (table) { + const char *param_name = value; + const char *param_value = NULL; + + if (param_name && param_name[0]) { + if ((param_value = (const char *)g_hash_table_lookup(table, param_name))) { + value = param_value; + } + } + } + + if (rule_data->node_hash != NULL) { + h_val = (const char *)g_hash_table_lookup(rule_data->node_hash, attr); + } + + if (attr_allocated) { + free((char *)attr); + attr = NULL; + } + + if (value != NULL && h_val != NULL) { + if (type == NULL) { + if (safe_str_eq(op, "lt") + || safe_str_eq(op, "lte") + || safe_str_eq(op, "gt") + || safe_str_eq(op, "gte")) { + type = "number"; + + } else { + type = "string"; + } + crm_trace("Defaulting to %s based comparison for '%s' op", type, op); + } + + if (safe_str_eq(type, "string")) { + cmp = strcasecmp(h_val, value); + + } else if (safe_str_eq(type, "number")) { + int h_val_f = crm_parse_int(h_val, NULL); + int value_f = crm_parse_int(value, NULL); + + if (h_val_f < value_f) { + cmp = -1; + } else if (h_val_f > value_f) { + cmp = 1; + } else { + cmp = 0; + } + + } else if (safe_str_eq(type, "version")) { + cmp = compare_version(h_val, value); + + } + + } else if (value == NULL && h_val == NULL) { + cmp = 0; + } else if (value == NULL) { + cmp = 1; + } else { + cmp = -1; + } + + if (safe_str_eq(op, "defined")) { + if (h_val != NULL) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "not_defined")) { + if (h_val == NULL) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "eq")) { + if ((h_val == value) || cmp == 0) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "ne")) { + if ((h_val == NULL && value != NULL) + || (h_val != NULL && value == NULL) + || cmp != 0) { + accept = TRUE; + } + + } else if (value == NULL || h_val == NULL) { + // The comparison is meaningless from this point on + accept = FALSE; + + } else if (safe_str_eq(op, "lt")) { + if (cmp < 0) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "lte")) { + if (cmp <= 0) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "gt")) { + if (cmp > 0) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "gte")) { + if (cmp >= 0) { + accept = TRUE; + } + } + + return accept; +} + +int +pe__eval_date_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change) +{ + crm_time_t *start = NULL; + crm_time_t *end = NULL; + const char *value = NULL; + const char *op = crm_element_value(expr, "operation"); + + xmlNode *duration_spec = NULL; + xmlNode *date_spec = NULL; + + // "undetermined" will also be returned for parsing errors + int rc = pcmk_rc_undetermined; + + crm_trace("Testing expression: %s", ID(expr)); + + duration_spec = first_named_child(expr, "duration"); + date_spec = first_named_child(expr, "date_spec"); + + value = crm_element_value(expr, "start"); + if (value != NULL) { + start = crm_time_new(value); + } + value = crm_element_value(expr, "end"); + if (value != NULL) { + end = crm_time_new(value); + } + + if (start != NULL && end == NULL && duration_spec != NULL) { + end = pe_parse_xml_duration(start, duration_spec); + } + + if ((op == NULL) || safe_str_eq(op, "in_range")) { + if ((start == NULL) && (end == NULL)) { + // in_range requires at least one of start or end + } else if ((start != NULL) && (crm_time_compare(rule_data->now, start) < 0)) { + rc = pcmk_rc_before_range; + crm_time_set_if_earlier(next_change, start); + } else if ((end != NULL) && (crm_time_compare(rule_data->now, end) > 0)) { + rc = pcmk_rc_after_range; + } else { + rc = pcmk_rc_within_range; + if (end && next_change) { + // Evaluation doesn't change until second after end + crm_time_add_seconds(end, 1); + crm_time_set_if_earlier(next_change, end); + } + } + + } else if (safe_str_eq(op, "date_spec")) { + rc = pe_cron_range_satisfied(rule_data->now, date_spec); + // @TODO set next_change appropriately + + } else if (safe_str_eq(op, "gt")) { + if (start == NULL) { + // gt requires start + } else if (crm_time_compare(rule_data->now, start) > 0) { + rc = pcmk_rc_within_range; + } else { + rc = pcmk_rc_before_range; + + // Evaluation doesn't change until second after start + crm_time_add_seconds(start, 1); + crm_time_set_if_earlier(next_change, start); + } + + } else if (safe_str_eq(op, "lt")) { + if (end == NULL) { + // lt requires end + } else if (crm_time_compare(rule_data->now, end) < 0) { + rc = pcmk_rc_within_range; + crm_time_set_if_earlier(next_change, end); + } else { + rc = pcmk_rc_after_range; + } + } + + crm_time_free(start); + crm_time_free(end); + return rc; +} + +gboolean +pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) +{ + gboolean accept = FALSE; + const char *op = NULL; + const char *value = NULL; + + if (rule_data->role == RSC_ROLE_UNKNOWN) { + return accept; + } + + value = crm_element_value(expr, XML_EXPR_ATTR_VALUE); + op = crm_element_value(expr, XML_EXPR_ATTR_OPERATION); + + if (safe_str_eq(op, "defined")) { + if (rule_data->role > RSC_ROLE_STARTED) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "not_defined")) { + if (rule_data->role < RSC_ROLE_SLAVE && rule_data->role > RSC_ROLE_UNKNOWN) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "eq")) { + if (text2role(value) == rule_data->role) { + accept = TRUE; + } + + } else if (safe_str_eq(op, "ne")) { + // Test "ne" only with promotable clone roles + if (rule_data->role < RSC_ROLE_SLAVE && rule_data->role > RSC_ROLE_UNKNOWN) { + accept = FALSE; + + } else if (text2role(value) != rule_data->role) { + accept = TRUE; + } + } + return accept; +} + // Deprecated functions kept only for backward API compatibility gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now); gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, -- 1.8.3.1 From 56a1337a54f3ba8a175ff3252658e1e43f7c670b Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 28 Apr 2020 14:34:40 -0400 Subject: [PATCH 03/17] Feature: scheduler: Add new rule tests for op_defaults and rsc_defaults. These are like all the other rule evaluating functions, but they do not have any wrappers for the older style API. --- include/crm/pengine/rules_internal.h | 2 ++ lib/pengine/rules.c | 68 ++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/include/crm/pengine/rules_internal.h b/include/crm/pengine/rules_internal.h index 8a22108..f60263a 100644 --- a/include/crm/pengine/rules_internal.h +++ b/include/crm/pengine/rules_internal.h @@ -24,7 +24,9 @@ crm_time_t *pe_parse_xml_duration(crm_time_t * start, xmlNode * duration_spec); gboolean pe__eval_attr_expr(xmlNode *expr, pe_rule_eval_data_t *rule_data); int pe__eval_date_expr(xmlNode *expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change); +gboolean pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data); gboolean pe__eval_role_expr(xmlNode *expr, pe_rule_eval_data_t *rule_data); +gboolean pe__eval_rsc_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data); int pe_eval_date_expression(xmlNode *time_expr, crm_time_t *now, diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index 3f316c2..a5af57a 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -1123,6 +1123,38 @@ pe__eval_date_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data, crm_time_t * } gboolean +pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) { + const char *name = crm_element_value(expr, XML_NVPAIR_ATTR_NAME); + const char *interval_s = crm_element_value(expr, XML_LRM_ATTR_INTERVAL); + guint interval; + + crm_trace("Testing op_defaults expression: %s", ID(expr)); + + if (rule_data->op_data == NULL) { + crm_trace("No operations data provided"); + return FALSE; + } + + interval = crm_parse_interval_spec(interval_s); + if (interval == 0 && errno != 0) { + crm_trace("Could not parse interval: %s", interval_s); + return FALSE; + } + + if (interval_s != NULL && interval != rule_data->op_data->interval) { + crm_trace("Interval doesn't match: %d != %d", interval, rule_data->op_data->interval); + return FALSE; + } + + if (!crm_str_eq(name, rule_data->op_data->op_name, TRUE)) { + crm_trace("Name doesn't match: %s != %s", name, rule_data->op_data->op_name); + return FALSE; + } + + return TRUE; +} + +gboolean pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) { gboolean accept = FALSE; @@ -1163,6 +1195,42 @@ pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) return accept; } +gboolean +pe__eval_rsc_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) +{ + const char *class = crm_element_value(expr, XML_AGENT_ATTR_CLASS); + const char *provider = crm_element_value(expr, XML_AGENT_ATTR_PROVIDER); + const char *type = crm_element_value(expr, XML_EXPR_ATTR_TYPE); + + crm_trace("Testing rsc_defaults expression: %s", ID(expr)); + + if (rule_data->rsc_data == NULL) { + crm_trace("No resource data provided"); + return FALSE; + } + + if (class != NULL && + !crm_str_eq(class, rule_data->rsc_data->standard, TRUE)) { + crm_trace("Class doesn't match: %s != %s", class, rule_data->rsc_data->standard); + return FALSE; + } + + if ((provider == NULL && rule_data->rsc_data->provider != NULL) || + (provider != NULL && rule_data->rsc_data->provider == NULL) || + !crm_str_eq(provider, rule_data->rsc_data->provider, TRUE)) { + crm_trace("Provider doesn't match: %s != %s", provider, rule_data->rsc_data->provider); + return FALSE; + } + + if (type != NULL && + !crm_str_eq(type, rule_data->rsc_data->agent, TRUE)) { + crm_trace("Agent doesn't match: %s != %s", type, rule_data->rsc_data->agent); + return FALSE; + } + + return TRUE; +} + // Deprecated functions kept only for backward API compatibility gboolean test_ruleset(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now); gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, -- 1.8.3.1 From 5a4da3f77feee0d3bac50e9adc4eb4b35724dfb2 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 28 Apr 2020 14:41:08 -0400 Subject: [PATCH 04/17] Refactor: scheduler: Reimplement core rule eval functions. The core functions of pe_evaluate_rules, pe_test_rule, and pe_test_expression have been turned into new, similarly named functions that take a pe_rule_eval_data_t as an argument. The old ones still exist as wrappers around the new ones. --- include/crm/pengine/rules.h | 7 ++ lib/pengine/rules.c | 259 ++++++++++++++++++++++++++------------------ 2 files changed, 162 insertions(+), 104 deletions(-) diff --git a/include/crm/pengine/rules.h b/include/crm/pengine/rules.h index d7bdbf9..a74c629 100644 --- a/include/crm/pengine/rules.h +++ b/include/crm/pengine/rules.h @@ -61,6 +61,13 @@ GHashTable *pe_unpack_versioned_parameters(xmlNode *versioned_params, const char char *pe_expand_re_matches(const char *string, pe_re_match_data_t * match_data); +gboolean pe_eval_rules(xmlNode *ruleset, pe_rule_eval_data_t *rule_data, + crm_time_t *next_change); +gboolean pe_eval_expr(xmlNode *rule, pe_rule_eval_data_t *rule_data, + crm_time_t *next_change); +gboolean pe_eval_subexpr(xmlNode *expr, pe_rule_eval_data_t *rule_data, + crm_time_t *next_change); + #ifndef PCMK__NO_COMPAT /* Everything here is deprecated and kept only for public API backward * compatibility. It will be moved to compatibility.h when 2.1.0 is released. diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index a5af57a..a6353ef 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -38,25 +38,16 @@ gboolean pe_evaluate_rules(xmlNode *ruleset, GHashTable *node_hash, crm_time_t *now, crm_time_t *next_change) { - // If there are no rules, pass by default - gboolean ruleset_default = TRUE; - - for (xmlNode *rule = first_named_child(ruleset, XML_TAG_RULE); - rule != NULL; rule = crm_next_same_xml(rule)) { + pe_rule_eval_data_t rule_data = { + .node_hash = node_hash, + .role = RSC_ROLE_UNKNOWN, + .now = now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; - ruleset_default = FALSE; - if (pe_test_rule(rule, node_hash, RSC_ROLE_UNKNOWN, now, next_change, - NULL)) { - /* Only the deprecated "lifetime" element of location constraints - * may contain more than one rule at the top level -- the schema - * limits a block of nvpairs to a single top-level rule. So, this - * effectively means that a lifetime is active if any rule it - * contains is active. - */ - return TRUE; - } - } - return ruleset_default; + return pe_eval_rules(ruleset, &rule_data, next_change); } gboolean @@ -64,44 +55,16 @@ pe_test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, crm_time_t *next_change, pe_match_data_t *match_data) { - xmlNode *expr = NULL; - gboolean test = TRUE; - gboolean empty = TRUE; - gboolean passed = TRUE; - gboolean do_and = TRUE; - const char *value = NULL; - - rule = expand_idref(rule, NULL); - value = crm_element_value(rule, XML_RULE_ATTR_BOOLEAN_OP); - if (safe_str_eq(value, "or")) { - do_and = FALSE; - passed = FALSE; - } - - crm_trace("Testing rule %s", ID(rule)); - for (expr = __xml_first_child_element(rule); expr != NULL; - expr = __xml_next_element(expr)) { - - test = pe_test_expression(expr, node_hash, role, now, next_change, - match_data); - empty = FALSE; - - if (test && do_and == FALSE) { - crm_trace("Expression %s/%s passed", ID(rule), ID(expr)); - return TRUE; - - } else if (test == FALSE && do_and) { - crm_trace("Expression %s/%s failed", ID(rule), ID(expr)); - return FALSE; - } - } - - if (empty) { - crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule)); - } + pe_rule_eval_data_t rule_data = { + .node_hash = node_hash, + .role = role, + .now = now, + .match_data = match_data, + .rsc_data = NULL, + .op_data = NULL + }; - crm_trace("Rule %s %s", ID(rule), passed ? "passed" : "failed"); - return passed; + return pe_eval_expr(rule, &rule_data, next_change); } /*! @@ -125,56 +88,16 @@ pe_test_expression(xmlNode *expr, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now, crm_time_t *next_change, pe_match_data_t *match_data) { - gboolean accept = FALSE; - const char *uname = NULL; - - switch (find_expression_type(expr)) { - case nested_rule: - accept = pe_test_rule(expr, node_hash, role, now, next_change, - match_data); - break; - case attr_expr: - case loc_expr: - /* these expressions can never succeed if there is - * no node to compare with - */ - if (node_hash != NULL) { - accept = pe_test_attr_expression(expr, node_hash, now, match_data); - } - break; - - case time_expr: - accept = pe_test_date_expression(expr, now, next_change); - break; - - case role_expr: - accept = pe_test_role_expression(expr, role, now); - break; - -#if ENABLE_VERSIONED_ATTRS - case version_expr: - if (node_hash && g_hash_table_lookup_extended(node_hash, - CRM_ATTR_RA_VERSION, - NULL, NULL)) { - accept = pe_test_attr_expression(expr, node_hash, now, NULL); - } else { - // we are going to test it when we have ra-version - accept = TRUE; - } - break; -#endif - - default: - CRM_CHECK(FALSE /* bad type */ , return FALSE); - accept = FALSE; - } - if (node_hash) { - uname = g_hash_table_lookup(node_hash, CRM_ATTR_UNAME); - } + pe_rule_eval_data_t rule_data = { + .node_hash = node_hash, + .role = role, + .now = now, + .match_data = match_data, + .rsc_data = NULL, + .op_data = NULL + }; - crm_trace("Expression %s %s on %s", - ID(expr), accept ? "passed" : "failed", uname ? uname : "all nodes"); - return accept; + return pe_eval_subexpr(expr, &rule_data, next_change); } enum expression_type @@ -885,6 +808,134 @@ pe_unpack_versioned_parameters(xmlNode *versioned_params, const char *ra_version #endif gboolean +pe_eval_rules(xmlNode *ruleset, pe_rule_eval_data_t *rule_data, crm_time_t *next_change) +{ + // If there are no rules, pass by default + gboolean ruleset_default = TRUE; + + for (xmlNode *rule = first_named_child(ruleset, XML_TAG_RULE); + rule != NULL; rule = crm_next_same_xml(rule)) { + + ruleset_default = FALSE; + if (pe_eval_expr(rule, rule_data, next_change)) { + /* Only the deprecated "lifetime" element of location constraints + * may contain more than one rule at the top level -- the schema + * limits a block of nvpairs to a single top-level rule. So, this + * effectively means that a lifetime is active if any rule it + * contains is active. + */ + return TRUE; + } + } + + return ruleset_default; +} + +gboolean +pe_eval_expr(xmlNode *rule, pe_rule_eval_data_t *rule_data, crm_time_t *next_change) +{ + xmlNode *expr = NULL; + gboolean test = TRUE; + gboolean empty = TRUE; + gboolean passed = TRUE; + gboolean do_and = TRUE; + const char *value = NULL; + + rule = expand_idref(rule, NULL); + value = crm_element_value(rule, XML_RULE_ATTR_BOOLEAN_OP); + if (safe_str_eq(value, "or")) { + do_and = FALSE; + passed = FALSE; + } + + crm_trace("Testing rule %s", ID(rule)); + for (expr = __xml_first_child_element(rule); expr != NULL; + expr = __xml_next_element(expr)) { + + test = pe_eval_subexpr(expr, rule_data, next_change); + empty = FALSE; + + if (test && do_and == FALSE) { + crm_trace("Expression %s/%s passed", ID(rule), ID(expr)); + return TRUE; + + } else if (test == FALSE && do_and) { + crm_trace("Expression %s/%s failed", ID(rule), ID(expr)); + return FALSE; + } + } + + if (empty) { + crm_err("Invalid Rule %s: rules must contain at least one expression", ID(rule)); + } + + crm_trace("Rule %s %s", ID(rule), passed ? "passed" : "failed"); + return passed; +} + +gboolean +pe_eval_subexpr(xmlNode *expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change) +{ + gboolean accept = FALSE; + const char *uname = NULL; + + switch (find_expression_type(expr)) { + case nested_rule: + accept = pe_eval_expr(expr, rule_data, next_change); + break; + case attr_expr: + case loc_expr: + /* these expressions can never succeed if there is + * no node to compare with + */ + if (rule_data->node_hash != NULL) { + accept = pe__eval_attr_expr(expr, rule_data); + } + break; + + case time_expr: + accept = pe_test_date_expression(expr, rule_data->now, next_change); + break; + + case role_expr: + accept = pe__eval_role_expr(expr, rule_data); + break; + + case rsc_expr: + accept = pe__eval_rsc_expr(expr, rule_data); + break; + + case op_expr: + accept = pe__eval_op_expr(expr, rule_data); + break; + +#if ENABLE_VERSIONED_ATTRS + case version_expr: + if (rule_data->node_hash && + g_hash_table_lookup_extended(rule_data->node_hash, + CRM_ATTR_RA_VERSION, NULL, NULL)) { + accept = pe__eval_attr_expr(expr, rule_data); + } else { + // we are going to test it when we have ra-version + accept = TRUE; + } + break; +#endif + + default: + CRM_CHECK(FALSE /* bad type */ , return FALSE); + accept = FALSE; + } + if (rule_data->node_hash) { + uname = g_hash_table_lookup(rule_data->node_hash, CRM_ATTR_UNAME); + } + + crm_trace("Expression %s %s on %s", + ID(expr), accept ? "passed" : "failed", uname ? uname : "all nodes"); + return accept; +} + +gboolean pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) { gboolean accept = FALSE; -- 1.8.3.1 From ea6318252164578fd27dcef657e80f5225337a4b Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Tue, 7 Apr 2020 15:57:06 -0400 Subject: [PATCH 05/17] Refactor: scheduler: Add rule_data to unpack_data_s. This is just to get rid of a couple extra arguments to some internal functions and make them look like the external functions. --- lib/pengine/rules.c | 65 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index a6353ef..2709d68 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -555,10 +555,9 @@ add_versioned_attributes(xmlNode * attr_set, xmlNode * versioned_attrs) typedef struct unpack_data_s { gboolean overwrite; - GHashTable *node_hash; void *hash; - crm_time_t *now; crm_time_t *next_change; + pe_rule_eval_data_t *rule_data; xmlNode *top; } unpack_data_t; @@ -568,14 +567,14 @@ unpack_attr_set(gpointer data, gpointer user_data) sorted_set_t *pair = data; unpack_data_t *unpack_data = user_data; - if (!pe_evaluate_rules(pair->attr_set, unpack_data->node_hash, - unpack_data->now, unpack_data->next_change)) { + if (!pe_eval_rules(pair->attr_set, unpack_data->rule_data, + unpack_data->next_change)) { return; } #if ENABLE_VERSIONED_ATTRS - if (get_versioned_rule(pair->attr_set) && !(unpack_data->node_hash && - g_hash_table_lookup_extended(unpack_data->node_hash, + if (get_versioned_rule(pair->attr_set) && !(unpack_data->rule_data->node_hash && + g_hash_table_lookup_extended(unpack_data->rule_data->node_hash, CRM_ATTR_RA_VERSION, NULL, NULL))) { // we haven't actually tested versioned expressions yet return; @@ -593,8 +592,8 @@ unpack_versioned_attr_set(gpointer data, gpointer user_data) sorted_set_t *pair = data; unpack_data_t *unpack_data = user_data; - if (pe_evaluate_rules(pair->attr_set, unpack_data->node_hash, - unpack_data->now, unpack_data->next_change)) { + if (pe_eval_rules(pair->attr_set, unpack_data->rule_data, + unpack_data->next_change)) { add_versioned_attributes(pair->attr_set, unpack_data->hash); } } @@ -658,19 +657,17 @@ make_pairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, * \param[in] top XML document root (used to expand id-ref's) * \param[in] xml_obj XML element containing blocks of nvpair elements * \param[in] set_name If not NULL, only use blocks of this element type - * \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 - * \param[in] now Time to use when evaluating rules + * \param[in] rule_data Matching parameters to use when unpacking * \param[out] next_change If not NULL, set to when rule evaluation will change * \param[in] unpack_func Function to call to unpack each block */ static void unpack_nvpair_blocks(xmlNode *top, xmlNode *xml_obj, const char *set_name, - GHashTable *node_hash, void *hash, - const char *always_first, gboolean overwrite, - crm_time_t *now, crm_time_t *next_change, + void *hash, const char *always_first, gboolean overwrite, + pe_rule_eval_data_t *rule_data, crm_time_t *next_change, GFunc unpack_func) { GList *pairs = make_pairs(top, xml_obj, set_name, always_first); @@ -678,11 +675,10 @@ unpack_nvpair_blocks(xmlNode *top, xmlNode *xml_obj, const char *set_name, if (pairs) { unpack_data_t data = { .hash = hash, - .node_hash = node_hash, - .now = now, .overwrite = overwrite, .next_change = next_change, .top = top, + .rule_data = rule_data }; g_list_foreach(pairs, unpack_func, &data); @@ -709,8 +705,17 @@ pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change) { - unpack_nvpair_blocks(top, xml_obj, set_name, node_hash, hash, always_first, - overwrite, now, next_change, unpack_attr_set); + pe_rule_eval_data_t rule_data = { + .node_hash = node_hash, + .role = RSC_ROLE_UNKNOWN, + .now = now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + + unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first, + overwrite, &rule_data, next_change, unpack_attr_set); } #if ENABLE_VERSIONED_ATTRS @@ -720,8 +725,17 @@ pe_unpack_versioned_attributes(xmlNode *top, xmlNode *xml_obj, xmlNode *hash, crm_time_t *now, crm_time_t *next_change) { - unpack_nvpair_blocks(top, xml_obj, set_name, node_hash, hash, NULL, FALSE, - now, next_change, unpack_versioned_attr_set); + pe_rule_eval_data_t rule_data = { + .node_hash = node_hash, + .role = RSC_ROLE_UNKNOWN, + .now = now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + + unpack_nvpair_blocks(top, xml_obj, set_name, hash, NULL, FALSE, + &rule_data, next_change, unpack_versioned_attr_set); } #endif @@ -1366,6 +1380,15 @@ unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, const char *always_first, gboolean overwrite, crm_time_t *now) { - unpack_nvpair_blocks(top, xml_obj, set_name, node_hash, hash, always_first, - overwrite, now, NULL, unpack_attr_set); + pe_rule_eval_data_t rule_data = { + .node_hash = node_hash, + .role = RSC_ROLE_UNKNOWN, + .now = now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + + unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first, + overwrite, &rule_data, NULL, unpack_attr_set); } -- 1.8.3.1 From 54646db6f5e4f1bb141b35798bcad5c3cc025afe Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 8 Apr 2020 10:41:41 -0400 Subject: [PATCH 06/17] Refactor: scheduler: Change args to pe__unpack_dataset_nvpairs. It should now take a pe_rule_eval_data_t instead of various separate arguments. This will allow passing further data that needs to be tested against in the future (such as rsc_defaults and op_defaults). It's also convenient to make versions of pe_unpack_nvpairs and pe_unpack_versioned_attributes that take the same arguments. Then, adapt callers of pe__unpack_dataset_nvpairs to pass the new argument. --- include/crm/pengine/internal.h | 2 +- include/crm/pengine/rules.h | 9 +++++++ lib/pengine/complex.c | 41 ++++++++++++++++++++++------- lib/pengine/rules.c | 23 ++++++++++++++-- lib/pengine/unpack.c | 33 ++++++++++++++++++++--- lib/pengine/utils.c | 60 +++++++++++++++++++++++++++++++----------- 6 files changed, 137 insertions(+), 31 deletions(-) diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h index 189ba7b..3e59502 100644 --- a/include/crm/pengine/internal.h +++ b/include/crm/pengine/internal.h @@ -460,7 +460,7 @@ void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set); void pe__register_messages(pcmk__output_t *out); void pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name, - GHashTable *node_hash, GHashTable *hash, + pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set); diff --git a/include/crm/pengine/rules.h b/include/crm/pengine/rules.h index a74c629..cbae8ed 100644 --- a/include/crm/pengine/rules.h +++ b/include/crm/pengine/rules.h @@ -46,12 +46,21 @@ gboolean pe_test_expression(xmlNode *expr, GHashTable *node_hash, crm_time_t *next_change, pe_match_data_t *match_data); +void pe_eval_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, + pe_rule_eval_data_t *rule_data, GHashTable *hash, + const char *always_first, gboolean overwrite, + crm_time_t *next_change); + void pe_unpack_nvpairs(xmlNode *top, 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); #if ENABLE_VERSIONED_ATTRS +void pe_eval_versioned_attributes(xmlNode *top, xmlNode *xml_obj, + const char *set_name, pe_rule_eval_data_t *rule_data, + xmlNode *hash, crm_time_t *next_change); + void pe_unpack_versioned_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, xmlNode *hash, crm_time_t *now, diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c index 16f3a71..d91c95e 100644 --- a/lib/pengine/complex.c +++ b/lib/pengine/complex.c @@ -95,10 +95,17 @@ void get_meta_attributes(GHashTable * meta_hash, pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set) { - GHashTable *node_hash = NULL; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; if (node) { - node_hash = node->details->attrs; + rule_data.node_hash = node->details->attrs; } if (rsc->xml) { @@ -112,7 +119,7 @@ get_meta_attributes(GHashTable * meta_hash, pe_resource_t * rsc, } } - pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_META_SETS, node_hash, + pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_META_SETS, &rule_data, meta_hash, NULL, FALSE, data_set); /* set anything else based on the parent */ @@ -122,20 +129,27 @@ get_meta_attributes(GHashTable * meta_hash, pe_resource_t * rsc, /* and finally check the defaults */ pe__unpack_dataset_nvpairs(data_set->rsc_defaults, XML_TAG_META_SETS, - node_hash, meta_hash, NULL, FALSE, data_set); + &rule_data, meta_hash, NULL, FALSE, data_set); } void get_rsc_attributes(GHashTable * meta_hash, pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set) { - GHashTable *node_hash = NULL; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; if (node) { - node_hash = node->details->attrs; + rule_data.node_hash = node->details->attrs; } - pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_ATTR_SETS, node_hash, + pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_ATTR_SETS, &rule_data, meta_hash, NULL, FALSE, data_set); /* set anything else based on the parent */ @@ -145,7 +159,7 @@ get_rsc_attributes(GHashTable * meta_hash, pe_resource_t * rsc, } else { /* and finally check the defaults */ pe__unpack_dataset_nvpairs(data_set->rsc_defaults, XML_TAG_ATTR_SETS, - node_hash, meta_hash, NULL, FALSE, data_set); + &rule_data, meta_hash, NULL, FALSE, data_set); } } @@ -376,6 +390,15 @@ common_unpack(xmlNode * xml_obj, pe_resource_t ** rsc, bool remote_node = FALSE; bool has_versioned_params = FALSE; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + crm_log_xml_trace(xml_obj, "Processing resource input..."); if (id == NULL) { @@ -706,7 +729,7 @@ common_unpack(xmlNode * xml_obj, pe_resource_t ** rsc, (*rsc)->utilization = crm_str_table_new(); - pe__unpack_dataset_nvpairs((*rsc)->xml, XML_TAG_UTILIZATION, NULL, + pe__unpack_dataset_nvpairs((*rsc)->xml, XML_TAG_UTILIZATION, &rule_data, (*rsc)->utilization, NULL, FALSE, data_set); /* data_set->resources = g_list_append(data_set->resources, (*rsc)); */ diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index 2709d68..7575011 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -686,6 +686,16 @@ unpack_nvpair_blocks(xmlNode *top, xmlNode *xml_obj, const char *set_name, } } +void +pe_eval_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, + pe_rule_eval_data_t *rule_data, GHashTable *hash, + const char *always_first, gboolean overwrite, + crm_time_t *next_change) +{ + unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first, + overwrite, rule_data, next_change, unpack_attr_set); +} + /*! * \brief Extract nvpair blocks contained by an XML element into a hash table * @@ -714,12 +724,21 @@ pe_unpack_nvpairs(xmlNode *top, xmlNode *xml_obj, const char *set_name, .op_data = NULL }; - unpack_nvpair_blocks(top, xml_obj, set_name, hash, always_first, - overwrite, &rule_data, next_change, unpack_attr_set); + pe_eval_nvpairs(top, xml_obj, set_name, &rule_data, hash, + always_first, overwrite, next_change); } #if ENABLE_VERSIONED_ATTRS void +pe_eval_versioned_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, + pe_rule_eval_data_t *rule_data, xmlNode *hash, + crm_time_t *next_change) +{ + unpack_nvpair_blocks(top, xml_obj, set_name, hash, NULL, FALSE, rule_data, + next_change, unpack_versioned_attr_set); +} + +void pe_unpack_versioned_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, xmlNode *hash, crm_time_t *now, diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c index 532a3e6..8784857 100644 --- a/lib/pengine/unpack.c +++ b/lib/pengine/unpack.c @@ -188,9 +188,18 @@ unpack_config(xmlNode * config, pe_working_set_t * data_set) const char *value = NULL; GHashTable *config_hash = crm_str_table_new(); + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + data_set->config_hash = config_hash; - pe__unpack_dataset_nvpairs(config, XML_CIB_TAG_PROPSET, NULL, config_hash, + pe__unpack_dataset_nvpairs(config, XML_CIB_TAG_PROPSET, &rule_data, config_hash, CIB_OPTIONS_FIRST, FALSE, data_set); verify_pe_options(data_set->config_hash); @@ -515,6 +524,15 @@ unpack_nodes(xmlNode * xml_nodes, pe_working_set_t * data_set) const char *type = NULL; const char *score = NULL; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + for (xml_obj = __xml_first_child_element(xml_nodes); xml_obj != NULL; xml_obj = __xml_next_element(xml_obj)) { @@ -547,7 +565,7 @@ unpack_nodes(xmlNode * xml_nodes, pe_working_set_t * data_set) handle_startup_fencing(data_set, new_node); add_node_attrs(xml_obj, new_node, FALSE, data_set); - pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_UTILIZATION, NULL, + pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_UTILIZATION, &rule_data, new_node->details->utilization, NULL, FALSE, data_set); @@ -3698,6 +3716,15 @@ add_node_attrs(xmlNode *xml_obj, pe_node_t *node, bool overwrite, { const char *cluster_name = NULL; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + g_hash_table_insert(node->details->attrs, strdup(CRM_ATTR_UNAME), strdup(node->details->uname)); @@ -3719,7 +3746,7 @@ add_node_attrs(xmlNode *xml_obj, pe_node_t *node, bool overwrite, strdup(cluster_name)); } - pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_ATTR_SETS, NULL, + pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_ATTR_SETS, &rule_data, node->details->attrs, NULL, overwrite, data_set); if (pe_node_attribute_raw(node, CRM_ATTR_SITE_NAME) == NULL) { diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index c9b45e0..d01936d 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -597,10 +597,19 @@ custom_action(pe_resource_t * rsc, char *key, const char *task, if (is_set(action->flags, pe_action_have_node_attrs) == FALSE && action->node != NULL && action->op_entry != NULL) { + pe_rule_eval_data_t rule_data = { + .node_hash = action->node->details->attrs, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + pe_set_action_bit(action, pe_action_have_node_attrs); pe__unpack_dataset_nvpairs(action->op_entry, XML_TAG_ATTR_SETS, - action->node->details->attrs, - action->extra, NULL, FALSE, data_set); + &rule_data, action->extra, NULL, + FALSE, data_set); } if (is_set(action->flags, pe_action_pseudo)) { @@ -873,6 +882,15 @@ pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set const char *timeout = NULL; int timeout_ms = 0; + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP); child != NULL; child = crm_next_same_xml(child)) { if (safe_str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME))) { @@ -884,7 +902,7 @@ pe_get_configured_timeout(pe_resource_t *rsc, const char *action, pe_working_set if (timeout == NULL && data_set->op_defaults) { GHashTable *action_meta = crm_str_table_new(); pe__unpack_dataset_nvpairs(data_set->op_defaults, XML_TAG_META_SETS, - NULL, action_meta, NULL, FALSE, data_set); + &rule_data, action_meta, NULL, FALSE, data_set); timeout = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT); } @@ -964,10 +982,19 @@ unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * contai pe_rsc_action_details_t *rsc_details = NULL; #endif + pe_rule_eval_data_t rule_data = { + .node_hash = NULL, + .role = RSC_ROLE_UNKNOWN, + .now = data_set->now, + .match_data = NULL, + .rsc_data = NULL, + .op_data = NULL + }; + CRM_CHECK(action && action->rsc, return); // Cluster-wide - pe__unpack_dataset_nvpairs(data_set->op_defaults, XML_TAG_META_SETS, NULL, + pe__unpack_dataset_nvpairs(data_set->op_defaults, XML_TAG_META_SETS, &rule_data, action->meta, NULL, FALSE, data_set); // Probe timeouts default differently, so handle timeout default later @@ -981,19 +1008,20 @@ unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * contai xmlAttrPtr xIter = NULL; // take precedence over defaults - pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_META_SETS, NULL, + pe__unpack_dataset_nvpairs(xml_obj, XML_TAG_META_SETS, &rule_data, action->meta, NULL, TRUE, data_set); #if ENABLE_VERSIONED_ATTRS rsc_details = pe_rsc_action_details(action); - pe_unpack_versioned_attributes(data_set->input, xml_obj, - XML_TAG_ATTR_SETS, NULL, - rsc_details->versioned_parameters, - data_set->now, NULL); - pe_unpack_versioned_attributes(data_set->input, xml_obj, - XML_TAG_META_SETS, NULL, - rsc_details->versioned_meta, - data_set->now, NULL); + + pe_eval_versioned_attributes(data_set->input, xml_obj, + XML_TAG_ATTR_SETS, &rule_data, + rsc_details->versioned_parameters, + NULL); + pe_eval_versioned_attributes(data_set->input, xml_obj, + XML_TAG_META_SETS, &rule_data, + rsc_details->versioned_meta, + NULL); #endif /* Anything set as an XML property has highest precedence. @@ -2693,14 +2721,14 @@ pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set) */ void pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name, - GHashTable *node_hash, GHashTable *hash, + pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pe_working_set_t *data_set) { crm_time_t *next_change = crm_time_new_undefined(); - pe_unpack_nvpairs(data_set->input, xml_obj, set_name, node_hash, hash, - always_first, overwrite, data_set->now, next_change); + pe_eval_nvpairs(data_set->input, xml_obj, set_name, rule_data, hash, + always_first, overwrite, next_change); if (crm_time_is_defined(next_change)) { time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change); -- 1.8.3.1 From ad06f60bae1fcb5d204fa18a0b21ade78aaee5f4 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 8 Apr 2020 13:43:26 -0400 Subject: [PATCH 07/17] Refactor: scheduler: unpack_operation should be static. --- lib/pengine/utils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index d01936d..c345875 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -23,8 +23,8 @@ extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root); void print_str_str(gpointer key, gpointer value, gpointer user_data); gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data); -void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container, - pe_working_set_t * data_set); +static void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container, + pe_working_set_t * data_set); static xmlNode *find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key, gboolean include_disabled); @@ -968,7 +968,7 @@ unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj, * \param[in] container Resource that contains affected resource, if any * \param[in] data_set Cluster state */ -void +static void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container, pe_working_set_t * data_set) { -- 1.8.3.1 From 7e57d955c9209af62dffc0639c50d51121028c26 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 8 Apr 2020 14:58:35 -0400 Subject: [PATCH 08/17] Refactor: scheduler: Pass interval to unpack_operation. --- lib/pengine/utils.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index c345875..1e3b0bd 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -24,7 +24,7 @@ extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root); void print_str_str(gpointer key, gpointer value, gpointer user_data); gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data); static void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container, - pe_working_set_t * data_set); + pe_working_set_t * data_set, guint interval_ms); static xmlNode *find_rsc_op_entry_helper(pe_resource_t * rsc, const char *key, gboolean include_disabled); @@ -568,9 +568,13 @@ custom_action(pe_resource_t * rsc, char *key, const char *task, } if (rsc != NULL) { + guint interval_ms = 0; + action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE); + parse_op_key(key, NULL, NULL, &interval_ms); - unpack_operation(action, action->op_entry, rsc->container, data_set); + unpack_operation(action, action->op_entry, rsc->container, data_set, + interval_ms); if (save_action) { rsc->actions = g_list_prepend(rsc->actions, action); @@ -963,20 +967,20 @@ unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj, * and start delay values as integer milliseconds), requirements, and * failure policy. * - * \param[in,out] action Action to unpack into - * \param[in] xml_obj Operation XML (or NULL if all defaults) - * \param[in] container Resource that contains affected resource, if any - * \param[in] data_set Cluster state + * \param[in,out] action Action to unpack into + * \param[in] xml_obj Operation XML (or NULL if all defaults) + * \param[in] container Resource that contains affected resource, if any + * \param[in] data_set Cluster state + * \param[in] interval_ms How frequently to perform the operation */ static void unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * container, - pe_working_set_t * data_set) + pe_working_set_t * data_set, guint interval_ms) { - guint interval_ms = 0; int timeout = 0; char *value_ms = NULL; const char *value = NULL; - const char *field = NULL; + const char *field = XML_LRM_ATTR_INTERVAL; char *default_timeout = NULL; #if ENABLE_VERSIONED_ATTRS pe_rsc_action_details_t *rsc_details = NULL; @@ -1038,23 +1042,11 @@ unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * contai g_hash_table_remove(action->meta, "id"); // Normalize interval to milliseconds - field = XML_LRM_ATTR_INTERVAL; - value = g_hash_table_lookup(action->meta, field); - if (value != NULL) { - interval_ms = crm_parse_interval_spec(value); - - } else if ((xml_obj == NULL) && !strcmp(action->task, RSC_STATUS)) { - /* An orphaned recurring monitor will not have any XML. However, we - * want the interval to be set, so the action can be properly detected - * as a recurring monitor. Parse it from the key in this case. - */ - parse_op_key(action->uuid, NULL, NULL, &interval_ms); - } if (interval_ms > 0) { value_ms = crm_strdup_printf("%u", interval_ms); g_hash_table_replace(action->meta, strdup(field), value_ms); - } else if (value) { + } else if (g_hash_table_lookup(action->meta, field) != NULL) { g_hash_table_remove(action->meta, field); } -- 1.8.3.1 From e4c411d9674e222647dd3ed31714c369f54ccad1 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Thu, 9 Apr 2020 16:15:17 -0400 Subject: [PATCH 09/17] Feature: scheduler: Pass rsc_defaults and op_defaults data. See: rhbz#1628701. --- lib/pengine/complex.c | 8 +++++++- lib/pengine/utils.c | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c index d91c95e..1f06348 100644 --- a/lib/pengine/complex.c +++ b/lib/pengine/complex.c @@ -95,12 +95,18 @@ void get_meta_attributes(GHashTable * meta_hash, pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set) { + pe_rsc_eval_data_t rsc_rule_data = { + .standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS), + .provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER), + .agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE) + }; + pe_rule_eval_data_t rule_data = { .node_hash = NULL, .role = RSC_ROLE_UNKNOWN, .now = data_set->now, .match_data = NULL, - .rsc_data = NULL, + .rsc_data = &rsc_rule_data, .op_data = NULL }; diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 1e3b0bd..d5309ed 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -986,13 +986,24 @@ unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * contai pe_rsc_action_details_t *rsc_details = NULL; #endif + pe_rsc_eval_data_t rsc_rule_data = { + .standard = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_CLASS), + .provider = crm_element_value(action->rsc->xml, XML_AGENT_ATTR_PROVIDER), + .agent = crm_element_value(action->rsc->xml, XML_EXPR_ATTR_TYPE) + }; + + pe_op_eval_data_t op_rule_data = { + .op_name = action->task, + .interval = interval_ms + }; + pe_rule_eval_data_t rule_data = { .node_hash = NULL, .role = RSC_ROLE_UNKNOWN, .now = data_set->now, .match_data = NULL, - .rsc_data = NULL, - .op_data = NULL + .rsc_data = &rsc_rule_data, + .op_data = &op_rule_data }; CRM_CHECK(action && action->rsc, return); -- 1.8.3.1 From 57eedcad739071530f01e1fd691734f7681a08a1 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 17 Apr 2020 12:30:51 -0400 Subject: [PATCH 10/17] Feature: xml: Add rsc_expression and op_expression to the XML schema. --- cts/cli/regression.upgrade.exp | 7 +- cts/cli/regression.validity.exp | 22 ++- xml/constraints-next.rng | 4 +- xml/nodes-3.4.rng | 44 +++++ xml/nvset-3.4.rng | 63 ++++++ xml/options-3.4.rng | 111 +++++++++++ xml/resources-3.4.rng | 425 ++++++++++++++++++++++++++++++++++++++++ xml/rule-3.4.rng | 165 ++++++++++++++++ 8 files changed, 833 insertions(+), 8 deletions(-) create mode 100644 xml/nodes-3.4.rng create mode 100644 xml/nvset-3.4.rng create mode 100644 xml/options-3.4.rng create mode 100644 xml/resources-3.4.rng create mode 100644 xml/rule-3.4.rng diff --git a/cts/cli/regression.upgrade.exp b/cts/cli/regression.upgrade.exp index 28ca057..50b22df 100644 --- a/cts/cli/regression.upgrade.exp +++ b/cts/cli/regression.upgrade.exp @@ -79,8 +79,11 @@ update_validation debug: Configuration valid for schema: pacemaker-3.2 update_validation debug: pacemaker-3.2-style configuration is also valid for pacemaker-3.3 update_validation debug: Testing 'pacemaker-3.3' validation (17 of X) update_validation debug: Configuration valid for schema: pacemaker-3.3 -update_validation trace: Stopping at pacemaker-3.3 -update_validation info: Transformed the configuration from pacemaker-2.10 to pacemaker-3.3 +update_validation debug: pacemaker-3.3-style configuration is also valid for pacemaker-3.4 +update_validation debug: Testing 'pacemaker-3.4' validation (18 of X) +update_validation debug: Configuration valid for schema: pacemaker-3.4 +update_validation trace: Stopping at pacemaker-3.4 +update_validation info: Transformed the configuration from pacemaker-2.10 to pacemaker-3.4 =#=#=#= Current cib after: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) =#=#=#= diff --git a/cts/cli/regression.validity.exp b/cts/cli/regression.validity.exp index 46e54b5..4407074 100644 --- a/cts/cli/regression.validity.exp +++ b/cts/cli/regression.validity.exp @@ -105,7 +105,11 @@ update_validation debug: Testing 'pacemaker-3.3' validation (17 of X) element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order update_validation trace: pacemaker-3.3 validation failed -Cannot upgrade configuration (claiming schema pacemaker-1.2) to at least pacemaker-3.0 because it does not validate with any schema from pacemaker-1.2 to pacemaker-3.3 +update_validation debug: Testing 'pacemaker-3.4' validation (18 of X) +element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order +element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order +update_validation trace: pacemaker-3.4 validation failed +Cannot upgrade configuration (claiming schema pacemaker-1.2) to at least pacemaker-3.0 because it does not validate with any schema from pacemaker-1.2 to pacemaker-3.4 =#=#=#= End test: Run crm_simulate with invalid CIB (enum violation) - Invalid configuration (78) =#=#=#= * Passed: crm_simulate - Run crm_simulate with invalid CIB (enum violation) =#=#=#= Begin test: Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#= @@ -198,7 +202,10 @@ update_validation trace: pacemaker-3.2 validation failed update_validation debug: Testing 'pacemaker-3.3' validation (17 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib update_validation trace: pacemaker-3.3 validation failed -Cannot upgrade configuration (claiming schema pacemaker-9999.0) to at least pacemaker-3.0 because it does not validate with any schema from unknown to pacemaker-3.3 +update_validation debug: Testing 'pacemaker-3.4' validation (18 of X) +element cib: Relax-NG validity error : Invalid attribute validate-with for element cib +update_validation trace: pacemaker-3.4 validation failed +Cannot upgrade configuration (claiming schema pacemaker-9999.0) to at least pacemaker-3.0 because it does not validate with any schema from unknown to pacemaker-3.4 =#=#=#= End test: Run crm_simulate with invalid CIB (unrecognized validate-with) - Invalid configuration (78) =#=#=#= * Passed: crm_simulate - Run crm_simulate with invalid CIB (unrecognized validate-with) =#=#=#= Begin test: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) =#=#=#= @@ -286,8 +293,11 @@ update_validation debug: Configuration valid for schema: pacemaker-3.2 update_validation debug: pacemaker-3.2-style configuration is also valid for pacemaker-3.3 update_validation debug: Testing 'pacemaker-3.3' validation (17 of X) update_validation debug: Configuration valid for schema: pacemaker-3.3 -update_validation trace: Stopping at pacemaker-3.3 -update_validation info: Transformed the configuration from pacemaker-1.2 to pacemaker-3.3 +update_validation debug: pacemaker-3.3-style configuration is also valid for pacemaker-3.4 +update_validation debug: Testing 'pacemaker-3.4' validation (18 of X) +update_validation debug: Configuration valid for schema: pacemaker-3.4 +update_validation trace: Stopping at pacemaker-3.4 +update_validation info: Transformed the configuration from pacemaker-1.2 to pacemaker-3.4 unpack_resources error: Resource start-up disabled since no STONITH resources have been defined unpack_resources error: Either configure some or disable STONITH with the stonith-enabled option unpack_resources error: NOTE: Clusters with shared data need STONITH to ensure data integrity @@ -393,6 +403,8 @@ element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order +element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order +element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order =#=#=#= Current cib after: Make resulting CIB invalid, and without validate-with attribute =#=#=#= @@ -450,6 +462,8 @@ validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attrib validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order +validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order +validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order unpack_resources error: Resource start-up disabled since no STONITH resources have been defined unpack_resources error: Either configure some or disable STONITH with the stonith-enabled option unpack_resources error: NOTE: Clusters with shared data need STONITH to ensure data integrity diff --git a/xml/constraints-next.rng b/xml/constraints-next.rng index 7e0d98e..1fa3e75 100644 --- a/xml/constraints-next.rng +++ b/xml/constraints-next.rng @@ -43,7 +43,7 @@ - + @@ -255,7 +255,7 @@ - + diff --git a/xml/nodes-3.4.rng b/xml/nodes-3.4.rng new file mode 100644 index 0000000..0132c72 --- /dev/null +++ b/xml/nodes-3.4.rng @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + member + ping + remote + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/nvset-3.4.rng b/xml/nvset-3.4.rng new file mode 100644 index 0000000..91a7d23 --- /dev/null +++ b/xml/nvset-3.4.rng @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/options-3.4.rng b/xml/options-3.4.rng new file mode 100644 index 0000000..22330d8 --- /dev/null +++ b/xml/options-3.4.rng @@ -0,0 +1,111 @@ + + + + + + + + + + + + cluster-infrastructure + + + + + + heartbeat + openais + classic openais + classic openais (with plugin) + cman + + + + + + + + + + + cluster-infrastructure + cluster_recheck_interval + dc_deadtime + default-action-timeout + default_action_timeout + default-migration-threshold + default_migration_threshold + default-resource-failure-stickiness + default_resource_failure_stickiness + default-resource-stickiness + default_resource_stickiness + election_timeout + expected-quorum-votes + is-managed-default + is_managed_default + no_quorum_policy + notification-agent + notification-recipient + remove_after_stop + shutdown_escalation + startup_fencing + stonith_action + stonith_enabled + stop_orphan_actions + stop_orphan_resources + symmetric_cluster + transition_idle_timeout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/resources-3.4.rng b/xml/resources-3.4.rng new file mode 100644 index 0000000..fbb4b65 --- /dev/null +++ b/xml/resources-3.4.rng @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + isolation + isolation-host + isolation-instance + isolation-wrapper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ([0-9\-]+) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + requires + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Stopped + Started + Slave + Master + + + + + + + ignore + block + stop + restart + standby + fence + restart-container + + + + + + + + + + + + + + ocf + + + + + lsb + heartbeat + stonith + upstart + service + systemd + nagios + + + + + diff --git a/xml/rule-3.4.rng b/xml/rule-3.4.rng new file mode 100644 index 0000000..5d1daf0 --- /dev/null +++ b/xml/rule-3.4.rng @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + or + and + + + + + + + + + + + + + + lt + gt + lte + gte + eq + ne + defined + not_defined + + + + + + + + + string + number + version + + + + + + + literal + param + meta + + + + + + + + + in_range + + + + + + + + + + + + + + + + + gt + + + + lt + + + + + + date_spec + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 1.8.3.1 From b0e2345d92fb7cf42c133b24457eeb07126db8a0 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Mon, 27 Apr 2020 16:24:22 -0400 Subject: [PATCH 11/17] Fix: scheduler: Change trace output in populate_hash. Only show the "Setting attribute:" text when it comes time to actually set the attribute. Also show the value being set. This makes it clearer that an attribute is actually being set, not just that the function is processing something. --- lib/pengine/rules.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c index 7575011..b0fca55 100644 --- a/lib/pengine/rules.c +++ b/lib/pengine/rules.c @@ -463,7 +463,6 @@ populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlN name = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_NAME); } - crm_trace("Setting attribute: %s", name); value = crm_element_value(an_attr, XML_NVPAIR_ATTR_VALUE); if (value == NULL) { value = crm_element_value(ref_nvpair, XML_NVPAIR_ATTR_VALUE); @@ -471,7 +470,6 @@ populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlN if (name == NULL || value == NULL) { continue; - } old_value = g_hash_table_lookup(hash, name); @@ -484,6 +482,7 @@ populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlN continue; } else if (old_value == NULL) { + crm_trace("Setting attribute: %s = %s", name, value); g_hash_table_insert(hash, strdup(name), strdup(value)); } else if (overwrite) { -- 1.8.3.1 From d35854384b231c79b8aba1ce4c5caf5dd51ec982 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 1 May 2020 15:45:31 -0400 Subject: [PATCH 12/17] Test: scheduler: Add a regression test for op_defaults. --- cts/cts-scheduler.in | 3 + cts/scheduler/op-defaults.dot | 33 ++++++ cts/scheduler/op-defaults.exp | 211 ++++++++++++++++++++++++++++++++++++++ cts/scheduler/op-defaults.scores | 11 ++ cts/scheduler/op-defaults.summary | 46 +++++++++ cts/scheduler/op-defaults.xml | 87 ++++++++++++++++ 6 files changed, 391 insertions(+) create mode 100644 cts/scheduler/op-defaults.dot create mode 100644 cts/scheduler/op-defaults.exp create mode 100644 cts/scheduler/op-defaults.scores create mode 100644 cts/scheduler/op-defaults.summary create mode 100644 cts/scheduler/op-defaults.xml diff --git a/cts/cts-scheduler.in b/cts/cts-scheduler.in index 5d72205..b83f812 100644 --- a/cts/cts-scheduler.in +++ b/cts/cts-scheduler.in @@ -962,6 +962,9 @@ TESTS = [ [ "shutdown-lock", "Ensure shutdown lock works properly" ], [ "shutdown-lock-expiration", "Ensure shutdown lock expiration works properly" ], ], + [ + [ "op-defaults", "Test op_defaults conditional expressions " ], + ], # @TODO: If pacemaker implements versioned attributes, uncomment these tests #[ diff --git a/cts/scheduler/op-defaults.dot b/cts/scheduler/op-defaults.dot new file mode 100644 index 0000000..5536c15 --- /dev/null +++ b/cts/scheduler/op-defaults.dot @@ -0,0 +1,33 @@ + digraph "g" { +"dummy-rsc_monitor_0 cluster01" -> "dummy-rsc_start_0 cluster02" [ style = bold] +"dummy-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_0 cluster02" -> "dummy-rsc_start_0 cluster02" [ style = bold] +"dummy-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_60000 cluster02" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_start_0 cluster02" -> "dummy-rsc_monitor_60000 cluster02" [ style = bold] +"dummy-rsc_start_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster01" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster02" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc2_monitor_0 cluster01" -> "ip-rsc2_start_0 cluster01" [ style = bold] +"ip-rsc2_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc2_monitor_0 cluster02" -> "ip-rsc2_start_0 cluster01" [ style = bold] +"ip-rsc2_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ip-rsc2_monitor_10000 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc2_start_0 cluster01" -> "ip-rsc2_monitor_10000 cluster01" [ style = bold] +"ip-rsc2_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_0 cluster01" -> "ip-rsc_start_0 cluster02" [ style = bold] +"ip-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_0 cluster02" -> "ip-rsc_start_0 cluster02" [ style = bold] +"ip-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_20000 cluster02" [ style=bold color="green" fontcolor="black"] +"ip-rsc_start_0 cluster02" -> "ip-rsc_monitor_20000 cluster02" [ style = bold] +"ip-rsc_start_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster01" -> "ping-rsc-ping_start_0 cluster01" [ style = bold] +"ping-rsc-ping_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster02" -> "ping-rsc-ping_start_0 cluster01" [ style = bold] +"ping-rsc-ping_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +} diff --git a/cts/scheduler/op-defaults.exp b/cts/scheduler/op-defaults.exp new file mode 100644 index 0000000..b81eacb --- /dev/null +++ b/cts/scheduler/op-defaults.exp @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cts/scheduler/op-defaults.scores b/cts/scheduler/op-defaults.scores new file mode 100644 index 0000000..1c622f0 --- /dev/null +++ b/cts/scheduler/op-defaults.scores @@ -0,0 +1,11 @@ +Allocation scores: +pcmk__native_allocate: dummy-rsc allocation score on cluster01: 0 +pcmk__native_allocate: dummy-rsc allocation score on cluster02: 0 +pcmk__native_allocate: fencing allocation score on cluster01: 0 +pcmk__native_allocate: fencing allocation score on cluster02: 0 +pcmk__native_allocate: ip-rsc allocation score on cluster01: 0 +pcmk__native_allocate: ip-rsc allocation score on cluster02: 0 +pcmk__native_allocate: ip-rsc2 allocation score on cluster01: 0 +pcmk__native_allocate: ip-rsc2 allocation score on cluster02: 0 +pcmk__native_allocate: ping-rsc-ping allocation score on cluster01: 0 +pcmk__native_allocate: ping-rsc-ping allocation score on cluster02: 0 diff --git a/cts/scheduler/op-defaults.summary b/cts/scheduler/op-defaults.summary new file mode 100644 index 0000000..b580939 --- /dev/null +++ b/cts/scheduler/op-defaults.summary @@ -0,0 +1,46 @@ + +Current cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Stopped + ip-rsc (ocf::heartbeat:IPaddr2): Stopped + ip-rsc2 (ocf::heartbeat:IPaddr2): Stopped + dummy-rsc (ocf::pacemaker:Dummy): Stopped + ping-rsc-ping (ocf::pacemaker:ping): Stopped + +Transition Summary: + * Start fencing ( cluster01 ) + * Start ip-rsc ( cluster02 ) + * Start ip-rsc2 ( cluster01 ) + * Start dummy-rsc ( cluster02 ) + * Start ping-rsc-ping ( cluster01 ) + +Executing cluster transition: + * Resource action: fencing monitor on cluster02 + * Resource action: fencing monitor on cluster01 + * Resource action: ip-rsc monitor on cluster02 + * Resource action: ip-rsc monitor on cluster01 + * Resource action: ip-rsc2 monitor on cluster02 + * Resource action: ip-rsc2 monitor on cluster01 + * Resource action: dummy-rsc monitor on cluster02 + * Resource action: dummy-rsc monitor on cluster01 + * Resource action: ping-rsc-ping monitor on cluster02 + * Resource action: ping-rsc-ping monitor on cluster01 + * Resource action: fencing start on cluster01 + * Resource action: ip-rsc start on cluster02 + * Resource action: ip-rsc2 start on cluster01 + * Resource action: dummy-rsc start on cluster02 + * Resource action: ping-rsc-ping start on cluster01 + * Resource action: ip-rsc monitor=20000 on cluster02 + * Resource action: ip-rsc2 monitor=10000 on cluster01 + * Resource action: dummy-rsc monitor=60000 on cluster02 + +Revised cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Started cluster01 + ip-rsc (ocf::heartbeat:IPaddr2): Started cluster02 + ip-rsc2 (ocf::heartbeat:IPaddr2): Started cluster01 + dummy-rsc (ocf::pacemaker:Dummy): Started cluster02 + ping-rsc-ping (ocf::pacemaker:ping): Started cluster01 + diff --git a/cts/scheduler/op-defaults.xml b/cts/scheduler/op-defaults.xml new file mode 100644 index 0000000..ae3b248 --- /dev/null +++ b/cts/scheduler/op-defaults.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 1.8.3.1 From 67067927bc1b8e000c06d2b5a4ae6b9223ca13c7 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 13 May 2020 10:40:34 -0400 Subject: [PATCH 13/17] Test: scheduler: Add a regression test for rsc_defaults. --- cts/cts-scheduler.in | 3 +- cts/scheduler/rsc-defaults.dot | 18 ++++++ cts/scheduler/rsc-defaults.exp | 124 +++++++++++++++++++++++++++++++++++++ cts/scheduler/rsc-defaults.scores | 11 ++++ cts/scheduler/rsc-defaults.summary | 38 ++++++++++++ cts/scheduler/rsc-defaults.xml | 78 +++++++++++++++++++++++ 6 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 cts/scheduler/rsc-defaults.dot create mode 100644 cts/scheduler/rsc-defaults.exp create mode 100644 cts/scheduler/rsc-defaults.scores create mode 100644 cts/scheduler/rsc-defaults.summary create mode 100644 cts/scheduler/rsc-defaults.xml diff --git a/cts/cts-scheduler.in b/cts/cts-scheduler.in index b83f812..9022ce9 100644 --- a/cts/cts-scheduler.in +++ b/cts/cts-scheduler.in @@ -963,7 +963,8 @@ TESTS = [ [ "shutdown-lock-expiration", "Ensure shutdown lock expiration works properly" ], ], [ - [ "op-defaults", "Test op_defaults conditional expressions " ], + [ "op-defaults", "Test op_defaults conditional expressions" ], + [ "rsc-defaults", "Test rsc_defaults conditional expressions" ], ], # @TODO: If pacemaker implements versioned attributes, uncomment these tests diff --git a/cts/scheduler/rsc-defaults.dot b/cts/scheduler/rsc-defaults.dot new file mode 100644 index 0000000..d776614 --- /dev/null +++ b/cts/scheduler/rsc-defaults.dot @@ -0,0 +1,18 @@ + digraph "g" { +"dummy-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster01" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster02" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc2_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc2_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster01" -> "ping-rsc-ping_start_0 cluster02" [ style = bold] +"ping-rsc-ping_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster02" -> "ping-rsc-ping_start_0 cluster02" [ style = bold] +"ping-rsc-ping_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_start_0 cluster02" [ style=bold color="green" fontcolor="black"] +} diff --git a/cts/scheduler/rsc-defaults.exp b/cts/scheduler/rsc-defaults.exp new file mode 100644 index 0000000..4aec360 --- /dev/null +++ b/cts/scheduler/rsc-defaults.exp @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cts/scheduler/rsc-defaults.scores b/cts/scheduler/rsc-defaults.scores new file mode 100644 index 0000000..e7f1bab --- /dev/null +++ b/cts/scheduler/rsc-defaults.scores @@ -0,0 +1,11 @@ +Allocation scores: +pcmk__native_allocate: dummy-rsc allocation score on cluster01: 0 +pcmk__native_allocate: dummy-rsc allocation score on cluster02: 0 +pcmk__native_allocate: fencing allocation score on cluster01: 0 +pcmk__native_allocate: fencing allocation score on cluster02: 0 +pcmk__native_allocate: ip-rsc allocation score on cluster01: -INFINITY +pcmk__native_allocate: ip-rsc allocation score on cluster02: -INFINITY +pcmk__native_allocate: ip-rsc2 allocation score on cluster01: -INFINITY +pcmk__native_allocate: ip-rsc2 allocation score on cluster02: -INFINITY +pcmk__native_allocate: ping-rsc-ping allocation score on cluster01: 0 +pcmk__native_allocate: ping-rsc-ping allocation score on cluster02: 0 diff --git a/cts/scheduler/rsc-defaults.summary b/cts/scheduler/rsc-defaults.summary new file mode 100644 index 0000000..0066f2e --- /dev/null +++ b/cts/scheduler/rsc-defaults.summary @@ -0,0 +1,38 @@ +2 of 5 resource instances DISABLED and 0 BLOCKED from further action due to failure + +Current cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Stopped + ip-rsc (ocf::heartbeat:IPaddr2): Stopped (disabled) + ip-rsc2 (ocf::heartbeat:IPaddr2): Stopped (disabled) + dummy-rsc (ocf::pacemaker:Dummy): Stopped (unmanaged) + ping-rsc-ping (ocf::pacemaker:ping): Stopped + +Transition Summary: + * Start fencing ( cluster01 ) + * Start ping-rsc-ping ( cluster02 ) + +Executing cluster transition: + * Resource action: fencing monitor on cluster02 + * Resource action: fencing monitor on cluster01 + * Resource action: ip-rsc monitor on cluster02 + * Resource action: ip-rsc monitor on cluster01 + * Resource action: ip-rsc2 monitor on cluster02 + * Resource action: ip-rsc2 monitor on cluster01 + * Resource action: dummy-rsc monitor on cluster02 + * Resource action: dummy-rsc monitor on cluster01 + * Resource action: ping-rsc-ping monitor on cluster02 + * Resource action: ping-rsc-ping monitor on cluster01 + * Resource action: fencing start on cluster01 + * Resource action: ping-rsc-ping start on cluster02 + +Revised cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Started cluster01 + ip-rsc (ocf::heartbeat:IPaddr2): Stopped (disabled) + ip-rsc2 (ocf::heartbeat:IPaddr2): Stopped (disabled) + dummy-rsc (ocf::pacemaker:Dummy): Stopped (unmanaged) + ping-rsc-ping (ocf::pacemaker:ping): Started cluster02 + diff --git a/cts/scheduler/rsc-defaults.xml b/cts/scheduler/rsc-defaults.xml new file mode 100644 index 0000000..38cae8b --- /dev/null +++ b/cts/scheduler/rsc-defaults.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 1.8.3.1 From bcfe068ccb3f3cb6cc3509257fbc4a59bc2b1a41 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 13 May 2020 12:47:35 -0400 Subject: [PATCH 14/17] Test: scheduler: Add a regression test for op_defaults with an AND expr. --- cts/cts-scheduler.in | 1 + cts/scheduler/op-defaults-2.dot | 33 ++++++ cts/scheduler/op-defaults-2.exp | 211 ++++++++++++++++++++++++++++++++++++ cts/scheduler/op-defaults-2.scores | 11 ++ cts/scheduler/op-defaults-2.summary | 46 ++++++++ cts/scheduler/op-defaults-2.xml | 73 +++++++++++++ 6 files changed, 375 insertions(+) create mode 100644 cts/scheduler/op-defaults-2.dot create mode 100644 cts/scheduler/op-defaults-2.exp create mode 100644 cts/scheduler/op-defaults-2.scores create mode 100644 cts/scheduler/op-defaults-2.summary create mode 100644 cts/scheduler/op-defaults-2.xml diff --git a/cts/cts-scheduler.in b/cts/cts-scheduler.in index 9022ce9..669b344 100644 --- a/cts/cts-scheduler.in +++ b/cts/cts-scheduler.in @@ -964,6 +964,7 @@ TESTS = [ ], [ [ "op-defaults", "Test op_defaults conditional expressions" ], + [ "op-defaults-2", "Test op_defaults AND'ed conditional expressions" ], [ "rsc-defaults", "Test rsc_defaults conditional expressions" ], ], diff --git a/cts/scheduler/op-defaults-2.dot b/cts/scheduler/op-defaults-2.dot new file mode 100644 index 0000000..5c67bd8 --- /dev/null +++ b/cts/scheduler/op-defaults-2.dot @@ -0,0 +1,33 @@ + digraph "g" { +"dummy-rsc_monitor_0 cluster01" -> "dummy-rsc_start_0 cluster02" [ style = bold] +"dummy-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_0 cluster02" -> "dummy-rsc_start_0 cluster02" [ style = bold] +"dummy-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_10000 cluster02" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_start_0 cluster02" -> "dummy-rsc_monitor_10000 cluster02" [ style = bold] +"dummy-rsc_start_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster01" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster02" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_0 cluster01" -> "ip-rsc_start_0 cluster02" [ style = bold] +"ip-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_0 cluster02" -> "ip-rsc_start_0 cluster02" [ style = bold] +"ip-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ip-rsc_monitor_20000 cluster02" [ style=bold color="green" fontcolor="black"] +"ip-rsc_start_0 cluster02" -> "ip-rsc_monitor_20000 cluster02" [ style = bold] +"ip-rsc_start_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster01" -> "ping-rsc-ping_start_0 cluster01" [ style = bold] +"ping-rsc-ping_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster02" -> "ping-rsc-ping_start_0 cluster01" [ style = bold] +"ping-rsc-ping_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +"rsc-passes_monitor_0 cluster01" -> "rsc-passes_start_0 cluster01" [ style = bold] +"rsc-passes_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"rsc-passes_monitor_0 cluster02" -> "rsc-passes_start_0 cluster01" [ style = bold] +"rsc-passes_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"rsc-passes_monitor_10000 cluster01" [ style=bold color="green" fontcolor="black"] +"rsc-passes_start_0 cluster01" -> "rsc-passes_monitor_10000 cluster01" [ style = bold] +"rsc-passes_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +} diff --git a/cts/scheduler/op-defaults-2.exp b/cts/scheduler/op-defaults-2.exp new file mode 100644 index 0000000..4324fde --- /dev/null +++ b/cts/scheduler/op-defaults-2.exp @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cts/scheduler/op-defaults-2.scores b/cts/scheduler/op-defaults-2.scores new file mode 100644 index 0000000..180c8b4 --- /dev/null +++ b/cts/scheduler/op-defaults-2.scores @@ -0,0 +1,11 @@ +Allocation scores: +pcmk__native_allocate: dummy-rsc allocation score on cluster01: 0 +pcmk__native_allocate: dummy-rsc allocation score on cluster02: 0 +pcmk__native_allocate: fencing allocation score on cluster01: 0 +pcmk__native_allocate: fencing allocation score on cluster02: 0 +pcmk__native_allocate: ip-rsc allocation score on cluster01: 0 +pcmk__native_allocate: ip-rsc allocation score on cluster02: 0 +pcmk__native_allocate: ping-rsc-ping allocation score on cluster01: 0 +pcmk__native_allocate: ping-rsc-ping allocation score on cluster02: 0 +pcmk__native_allocate: rsc-passes allocation score on cluster01: 0 +pcmk__native_allocate: rsc-passes allocation score on cluster02: 0 diff --git a/cts/scheduler/op-defaults-2.summary b/cts/scheduler/op-defaults-2.summary new file mode 100644 index 0000000..16a68be --- /dev/null +++ b/cts/scheduler/op-defaults-2.summary @@ -0,0 +1,46 @@ + +Current cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Stopped + ip-rsc (ocf::heartbeat:IPaddr2): Stopped + rsc-passes (ocf::heartbeat:IPaddr2): Stopped + dummy-rsc (ocf::pacemaker:Dummy): Stopped + ping-rsc-ping (ocf::pacemaker:ping): Stopped + +Transition Summary: + * Start fencing ( cluster01 ) + * Start ip-rsc ( cluster02 ) + * Start rsc-passes ( cluster01 ) + * Start dummy-rsc ( cluster02 ) + * Start ping-rsc-ping ( cluster01 ) + +Executing cluster transition: + * Resource action: fencing monitor on cluster02 + * Resource action: fencing monitor on cluster01 + * Resource action: ip-rsc monitor on cluster02 + * Resource action: ip-rsc monitor on cluster01 + * Resource action: rsc-passes monitor on cluster02 + * Resource action: rsc-passes monitor on cluster01 + * Resource action: dummy-rsc monitor on cluster02 + * Resource action: dummy-rsc monitor on cluster01 + * Resource action: ping-rsc-ping monitor on cluster02 + * Resource action: ping-rsc-ping monitor on cluster01 + * Resource action: fencing start on cluster01 + * Resource action: ip-rsc start on cluster02 + * Resource action: rsc-passes start on cluster01 + * Resource action: dummy-rsc start on cluster02 + * Resource action: ping-rsc-ping start on cluster01 + * Resource action: ip-rsc monitor=20000 on cluster02 + * Resource action: rsc-passes monitor=10000 on cluster01 + * Resource action: dummy-rsc monitor=10000 on cluster02 + +Revised cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Started cluster01 + ip-rsc (ocf::heartbeat:IPaddr2): Started cluster02 + rsc-passes (ocf::heartbeat:IPaddr2): Started cluster01 + dummy-rsc (ocf::pacemaker:Dummy): Started cluster02 + ping-rsc-ping (ocf::pacemaker:ping): Started cluster01 + diff --git a/cts/scheduler/op-defaults-2.xml b/cts/scheduler/op-defaults-2.xml new file mode 100644 index 0000000..9f3c288 --- /dev/null +++ b/cts/scheduler/op-defaults-2.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 1.8.3.1 From 017b783c2037d641c40a39dd7ec3a9eba0aaa6df Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 13 May 2020 15:18:28 -0400 Subject: [PATCH 15/17] Doc: Pacemaker Explained: Add documentation for rsc_expr and op_expr. --- doc/Pacemaker_Explained/en-US/Ch-Rules.txt | 174 +++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/doc/Pacemaker_Explained/en-US/Ch-Rules.txt b/doc/Pacemaker_Explained/en-US/Ch-Rules.txt index 9d617f6..5df5f82 100644 --- a/doc/Pacemaker_Explained/en-US/Ch-Rules.txt +++ b/doc/Pacemaker_Explained/en-US/Ch-Rules.txt @@ -522,6 +522,124 @@ You may wish to write +end="2005-03-31T23:59:59"+ to avoid confusion. ------- ===== +== Resource Expressions == + +An +rsc_expression+ is a rule condition based on a resource agent's properties. +This rule is only valid within an +rsc_defaults+ or +op_defaults+ context. None +of the matching attributes of +class+, +provider+, and +type+ are required. If +one is omitted, all values of that attribute will match. For instance, omitting ++type+ means every type will match. + +.Attributes of an rsc_expression Element +[width="95%",cols="2m,<5",options="header",align="center"] +|========================================================= + +|Field +|Description + +|id +|A unique name for the expression (required) + indexterm:[XML attribute,id attribute,rsc_expression element] + indexterm:[XML element,rsc_expression element,id attribute] + +|class +|The standard name to be matched against resource agents + indexterm:[XML attribute,class attribute,rsc_expression element] + indexterm:[XML element,rsc_expression element,class attribute] + +|provider +|If given, the vendor to be matched against resource agents. This + only makes sense for agents using the OCF spec. + indexterm:[XML attribute,provider attribute,rsc_expression element] + indexterm:[XML element,rsc_expression element,provider attribute] + +|type +|The name of the resource agent to be matched + indexterm:[XML attribute,type attribute,rsc_expression element] + indexterm:[XML element,rsc_expression element,type attribute] + +|========================================================= + +=== Example Resource-Based Expressions === + +A small sample of how resource-based expressions can be used: + +.True for all ocf:heartbeat:IPaddr2 resources +==== +[source,XML] +---- + + + +---- +==== + +.Provider doesn't apply to non-OCF resources +==== +[source,XML] +---- + + + +---- +==== + +== Operation Expressions == + +An +op_expression+ is a rule condition based on an action of some resource +agent. This rule is only valid within an +op_defaults+ context. + +.Attributes of an op_expression Element +[width="95%",cols="2m,<5",options="header",align="center"] +|========================================================= + +|Field +|Description + +|id +|A unique name for the expression (required) + indexterm:[XML attribute,id attribute,op_expression element] + indexterm:[XML element,op_expression element,id attribute] + +|name +|The action name to match against. This can be any action supported by + the resource agent; common values include +monitor+, +start+, and +stop+ + (required). + indexterm:[XML attribute,name attribute,op_expression element] + indexterm:[XML element,op_expression element,name attribute] + +|interval +|The interval of the action to match against. If not given, only + the name attribute will be used to match. + indexterm:[XML attribute,interval attribute,op_expression element] + indexterm:[XML element,op_expression element,interval attribute] + +|========================================================= + +=== Example Operation-Based Expressions === + +A small sample of how operation-based expressions can be used: + +.True for all monitor actions +==== +[source,XML] +---- + + + +---- +==== + +.True for all monitor actions with a 10 second interval +==== +[source,XML] +---- + + + +---- +==== + == Using Rules to Determine Resource Location == indexterm:[Rule,Determine Resource Location] indexterm:[Resource,Location,Determine by Rules] @@ -710,6 +828,62 @@ Rules may be used similarly in +instance_attributes+ or +utilization+ blocks. Any single block may directly contain only a single rule, but that rule may itself contain any number of rules. ++rsc_expression+ and +op_expression+ blocks may additionally be used to set defaults +on either a single resource or across an entire class of resources with a single +rule. +rsc_expression+ may be used to select resource agents within both +rsc_defaults+ +and +op_defaults+, while +op_expression+ may only be used within +op_defaults+. If +multiple rules succeed for a given resource agent, the last one specified will be +the one that takes effect. As with any other rule, boolean operations may be used +to make more complicated expressions. + +.Set all IPaddr2 resources to stopped +===== +[source,XML] +------- + + + + + + + + +------- +===== + +.Set all monitor action timeouts to 7 seconds +===== +[source,XML] +------- + + + + + + + + +------- +===== + +.Set the monitor action timeout on all IPaddr2 resources with a given monitor interval to 8 seconds +===== +[source,XML] +------- + + + + + + + + + +------- +===== + === Using Rules to Control Cluster Options === indexterm:[Rule,Controlling Cluster Options] indexterm:[Cluster,Setting Options with Rules] -- 1.8.3.1 From b8dd16c5e454445f73416ae8b74649545ee1b472 Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 13 May 2020 16:26:21 -0400 Subject: [PATCH 16/17] Test: scheduler: Add a test for multiple rules applying to the same resource. --- cts/cts-scheduler.in | 1 + cts/scheduler/op-defaults-3.dot | 14 +++++++ cts/scheduler/op-defaults-3.exp | 83 +++++++++++++++++++++++++++++++++++++ cts/scheduler/op-defaults-3.scores | 5 +++ cts/scheduler/op-defaults-3.summary | 26 ++++++++++++ cts/scheduler/op-defaults-3.xml | 54 ++++++++++++++++++++++++ 6 files changed, 183 insertions(+) create mode 100644 cts/scheduler/op-defaults-3.dot create mode 100644 cts/scheduler/op-defaults-3.exp create mode 100644 cts/scheduler/op-defaults-3.scores create mode 100644 cts/scheduler/op-defaults-3.summary create mode 100644 cts/scheduler/op-defaults-3.xml diff --git a/cts/cts-scheduler.in b/cts/cts-scheduler.in index 669b344..2c2d14f 100644 --- a/cts/cts-scheduler.in +++ b/cts/cts-scheduler.in @@ -965,6 +965,7 @@ TESTS = [ [ [ "op-defaults", "Test op_defaults conditional expressions" ], [ "op-defaults-2", "Test op_defaults AND'ed conditional expressions" ], + [ "op-defaults-3", "Test op_defaults precedence" ], [ "rsc-defaults", "Test rsc_defaults conditional expressions" ], ], diff --git a/cts/scheduler/op-defaults-3.dot b/cts/scheduler/op-defaults-3.dot new file mode 100644 index 0000000..382f630 --- /dev/null +++ b/cts/scheduler/op-defaults-3.dot @@ -0,0 +1,14 @@ + digraph "g" { +"dummy-rsc_monitor_0 cluster01" -> "dummy-rsc_start_0 cluster02" [ style = bold] +"dummy-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_0 cluster02" -> "dummy-rsc_start_0 cluster02" [ style = bold] +"dummy-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_10000 cluster02" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_start_0 cluster02" -> "dummy-rsc_monitor_10000 cluster02" [ style = bold] +"dummy-rsc_start_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster01" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster02" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +} diff --git a/cts/scheduler/op-defaults-3.exp b/cts/scheduler/op-defaults-3.exp new file mode 100644 index 0000000..6d567dc --- /dev/null +++ b/cts/scheduler/op-defaults-3.exp @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cts/scheduler/op-defaults-3.scores b/cts/scheduler/op-defaults-3.scores new file mode 100644 index 0000000..0a5190a --- /dev/null +++ b/cts/scheduler/op-defaults-3.scores @@ -0,0 +1,5 @@ +Allocation scores: +pcmk__native_allocate: dummy-rsc allocation score on cluster01: 0 +pcmk__native_allocate: dummy-rsc allocation score on cluster02: 0 +pcmk__native_allocate: fencing allocation score on cluster01: 0 +pcmk__native_allocate: fencing allocation score on cluster02: 0 diff --git a/cts/scheduler/op-defaults-3.summary b/cts/scheduler/op-defaults-3.summary new file mode 100644 index 0000000..a83eb15 --- /dev/null +++ b/cts/scheduler/op-defaults-3.summary @@ -0,0 +1,26 @@ + +Current cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Stopped + dummy-rsc (ocf::pacemaker:Dummy): Stopped + +Transition Summary: + * Start fencing ( cluster01 ) + * Start dummy-rsc ( cluster02 ) + +Executing cluster transition: + * Resource action: fencing monitor on cluster02 + * Resource action: fencing monitor on cluster01 + * Resource action: dummy-rsc monitor on cluster02 + * Resource action: dummy-rsc monitor on cluster01 + * Resource action: fencing start on cluster01 + * Resource action: dummy-rsc start on cluster02 + * Resource action: dummy-rsc monitor=10000 on cluster02 + +Revised cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Started cluster01 + dummy-rsc (ocf::pacemaker:Dummy): Started cluster02 + diff --git a/cts/scheduler/op-defaults-3.xml b/cts/scheduler/op-defaults-3.xml new file mode 100644 index 0000000..4a8912e --- /dev/null +++ b/cts/scheduler/op-defaults-3.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 1.8.3.1 From b9ccde16609e7d005ac0578a603da97a1808704a Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Fri, 15 May 2020 13:48:47 -0400 Subject: [PATCH 17/17] Test: scheduler: Add a test for rsc_defaults not specifying type. --- cts/cts-scheduler.in | 1 + cts/scheduler/rsc-defaults-2.dot | 11 ++++++ cts/scheduler/rsc-defaults-2.exp | 72 ++++++++++++++++++++++++++++++++++++ cts/scheduler/rsc-defaults-2.scores | 7 ++++ cts/scheduler/rsc-defaults-2.summary | 27 ++++++++++++++ cts/scheduler/rsc-defaults-2.xml | 52 ++++++++++++++++++++++++++ 6 files changed, 170 insertions(+) create mode 100644 cts/scheduler/rsc-defaults-2.dot create mode 100644 cts/scheduler/rsc-defaults-2.exp create mode 100644 cts/scheduler/rsc-defaults-2.scores create mode 100644 cts/scheduler/rsc-defaults-2.summary create mode 100644 cts/scheduler/rsc-defaults-2.xml diff --git a/cts/cts-scheduler.in b/cts/cts-scheduler.in index 2c2d14f..346ada2 100644 --- a/cts/cts-scheduler.in +++ b/cts/cts-scheduler.in @@ -967,6 +967,7 @@ TESTS = [ [ "op-defaults-2", "Test op_defaults AND'ed conditional expressions" ], [ "op-defaults-3", "Test op_defaults precedence" ], [ "rsc-defaults", "Test rsc_defaults conditional expressions" ], + [ "rsc-defaults-2", "Test rsc_defaults conditional expressions without type" ], ], # @TODO: If pacemaker implements versioned attributes, uncomment these tests diff --git a/cts/scheduler/rsc-defaults-2.dot b/cts/scheduler/rsc-defaults-2.dot new file mode 100644 index 0000000..b43c5e6 --- /dev/null +++ b/cts/scheduler/rsc-defaults-2.dot @@ -0,0 +1,11 @@ + digraph "g" { +"dummy-rsc_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"dummy-rsc_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster01" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"fencing_monitor_0 cluster02" -> "fencing_start_0 cluster01" [ style = bold] +"fencing_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +"fencing_start_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster01" [ style=bold color="green" fontcolor="black"] +"ping-rsc-ping_monitor_0 cluster02" [ style=bold color="green" fontcolor="black"] +} diff --git a/cts/scheduler/rsc-defaults-2.exp b/cts/scheduler/rsc-defaults-2.exp new file mode 100644 index 0000000..e9e1b5f --- /dev/null +++ b/cts/scheduler/rsc-defaults-2.exp @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cts/scheduler/rsc-defaults-2.scores b/cts/scheduler/rsc-defaults-2.scores new file mode 100644 index 0000000..4b70f54 --- /dev/null +++ b/cts/scheduler/rsc-defaults-2.scores @@ -0,0 +1,7 @@ +Allocation scores: +pcmk__native_allocate: dummy-rsc allocation score on cluster01: 0 +pcmk__native_allocate: dummy-rsc allocation score on cluster02: 0 +pcmk__native_allocate: fencing allocation score on cluster01: 0 +pcmk__native_allocate: fencing allocation score on cluster02: 0 +pcmk__native_allocate: ping-rsc-ping allocation score on cluster01: 0 +pcmk__native_allocate: ping-rsc-ping allocation score on cluster02: 0 diff --git a/cts/scheduler/rsc-defaults-2.summary b/cts/scheduler/rsc-defaults-2.summary new file mode 100644 index 0000000..46a2a2d --- /dev/null +++ b/cts/scheduler/rsc-defaults-2.summary @@ -0,0 +1,27 @@ + +Current cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Stopped + dummy-rsc (ocf::pacemaker:Dummy): Stopped (unmanaged) + ping-rsc-ping (ocf::pacemaker:ping): Stopped (unmanaged) + +Transition Summary: + * Start fencing ( cluster01 ) + +Executing cluster transition: + * Resource action: fencing monitor on cluster02 + * Resource action: fencing monitor on cluster01 + * Resource action: dummy-rsc monitor on cluster02 + * Resource action: dummy-rsc monitor on cluster01 + * Resource action: ping-rsc-ping monitor on cluster02 + * Resource action: ping-rsc-ping monitor on cluster01 + * Resource action: fencing start on cluster01 + +Revised cluster status: +Online: [ cluster01 cluster02 ] + + fencing (stonith:fence_xvm): Started cluster01 + dummy-rsc (ocf::pacemaker:Dummy): Stopped (unmanaged) + ping-rsc-ping (ocf::pacemaker:ping): Stopped (unmanaged) + diff --git a/cts/scheduler/rsc-defaults-2.xml b/cts/scheduler/rsc-defaults-2.xml new file mode 100644 index 0000000..a160fae --- /dev/null +++ b/cts/scheduler/rsc-defaults-2.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 1.8.3.1