797fe504a7
- Pacemaker Remote nodes can validate against later schema versions - Resolves: RHEL-7597 - Related: RHEL-17224
2335 lines
85 KiB
Diff
2335 lines
85 KiB
Diff
From a59d703de97a49a27564f572dac52b455b356ba9 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 12:14:57 -0400
|
|
Subject: [PATCH 01/20] Refactor: libcrmcommon: Remove prototypes for internal
|
|
functions.
|
|
|
|
These are only here to give a place to put the G_GNUC_PRINTF attribute,
|
|
but that can go in the function definition itself.
|
|
---
|
|
lib/common/schemas.c | 12 ++----------
|
|
1 file changed, 2 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index b3c09eb..a85438c 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -64,11 +64,7 @@ static struct schema_s *known_schemas = NULL;
|
|
static int xml_schema_max = 0;
|
|
static bool silent_logging = FALSE;
|
|
|
|
-static void
|
|
-xml_log(int priority, const char *fmt, ...)
|
|
-G_GNUC_PRINTF(2, 3);
|
|
-
|
|
-static void
|
|
+static void G_GNUC_PRINTF(2, 3)
|
|
xml_log(int priority, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
@@ -716,10 +712,6 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
return FALSE;
|
|
}
|
|
|
|
-static void
|
|
-cib_upgrade_err(void *ctx, const char *fmt, ...)
|
|
-G_GNUC_PRINTF(2, 3);
|
|
-
|
|
/* With this arrangement, an attempt to identify the message severity
|
|
as explicitly signalled directly from XSLT is performed in rather
|
|
a smart way (no reliance on formatting string + arguments being
|
|
@@ -743,7 +735,7 @@ G_GNUC_PRINTF(2, 3);
|
|
(suspicious, likely internal errors or some runaways) is
|
|
LOG_WARNING.
|
|
*/
|
|
-static void
|
|
+static void G_GNUC_PRINTF(2, 3)
|
|
cib_upgrade_err(void *ctx, const char *fmt, ...)
|
|
{
|
|
va_list ap, aq;
|
|
--
|
|
2.31.1
|
|
|
|
From 3d50aeebce74e520606036ec7db8b5c70fe327b5 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 12:54:37 -0400
|
|
Subject: [PATCH 02/20] Refactor: libcrmcommon: validate_with should take a
|
|
schema as argument.
|
|
|
|
...instead of taking an index, and then finding that in the
|
|
known_schemas array.
|
|
---
|
|
lib/common/schemas.c | 25 ++++++++++++-------------
|
|
1 file changed, 12 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index a85438c..f1f86f4 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -555,18 +555,16 @@ crm_schema_cleanup(void)
|
|
}
|
|
|
|
static gboolean
|
|
-validate_with(xmlNode *xml, int method, xmlRelaxNGValidityErrorFunc error_handler, void* error_handler_context)
|
|
+validate_with(xmlNode *xml, struct schema_s *schema, xmlRelaxNGValidityErrorFunc error_handler, void* error_handler_context)
|
|
{
|
|
gboolean valid = FALSE;
|
|
char *file = NULL;
|
|
- struct schema_s *schema = NULL;
|
|
relaxng_ctx_cache_t **cache = NULL;
|
|
|
|
- if (method < 0) {
|
|
+ if (schema == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
- schema = &(known_schemas[method]);
|
|
if (schema->validator == schema_validator_none) {
|
|
return TRUE;
|
|
}
|
|
@@ -587,8 +585,7 @@ validate_with(xmlNode *xml, int method, xmlRelaxNGValidityErrorFunc error_handle
|
|
valid = validate_with_relaxng(xml->doc, error_handler, error_handler_context, file, cache);
|
|
break;
|
|
default:
|
|
- crm_err("Unknown validator type: %d",
|
|
- known_schemas[method].validator);
|
|
+ crm_err("Unknown validator type: %d", schema->validator);
|
|
break;
|
|
}
|
|
|
|
@@ -597,11 +594,11 @@ validate_with(xmlNode *xml, int method, xmlRelaxNGValidityErrorFunc error_handle
|
|
}
|
|
|
|
static bool
|
|
-validate_with_silent(xmlNode *xml, int method)
|
|
+validate_with_silent(xmlNode *xml, struct schema_s *schema)
|
|
{
|
|
bool rc, sl_backup = silent_logging;
|
|
silent_logging = TRUE;
|
|
- rc = validate_with(xml, method, (xmlRelaxNGValidityErrorFunc) xml_log, GUINT_TO_POINTER(LOG_ERR));
|
|
+ rc = validate_with(xml, schema, (xmlRelaxNGValidityErrorFunc) xml_log, GUINT_TO_POINTER(LOG_ERR));
|
|
silent_logging = sl_backup;
|
|
return rc;
|
|
}
|
|
@@ -687,7 +684,7 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
bool valid = FALSE;
|
|
|
|
for (lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
- if (validate_with(xml_blob, lpc, NULL, NULL)) {
|
|
+ if (validate_with(xml_blob, &known_schemas[lpc], NULL, NULL)) {
|
|
valid = TRUE;
|
|
crm_xml_add(xml_blob, XML_ATTR_VALIDATION,
|
|
known_schemas[lpc].name);
|
|
@@ -705,7 +702,8 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
if (strcmp(validation, PCMK__VALUE_NONE) == 0) {
|
|
return TRUE;
|
|
} else if (version < xml_schema_max) {
|
|
- return validate_with(xml_blob, version, error_handler, error_handler_context);
|
|
+ return validate_with(xml_blob, version >= 0 ? &known_schemas[version] : NULL,
|
|
+ error_handler, error_handler_context);
|
|
}
|
|
|
|
crm_err("Unknown validator: %s", validation);
|
|
@@ -1019,7 +1017,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>",
|
|
lpc, max_stable_schemas);
|
|
|
|
- if (validate_with(xml, lpc, error_handler, GUINT_TO_POINTER(LOG_ERR)) == FALSE) {
|
|
+ if (validate_with(xml, &known_schemas[lpc], error_handler, GUINT_TO_POINTER(LOG_ERR)) == FALSE) {
|
|
if (next != -1) {
|
|
crm_info("Configuration not valid for schema: %s",
|
|
known_schemas[lpc].name);
|
|
@@ -1067,7 +1065,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
version boundary, as X.0 "transitional" version is
|
|
expected to be more strict than it's successors that
|
|
may re-allow constructs from previous major line) */
|
|
- || validate_with_silent(xml, next)) {
|
|
+ || validate_with_silent(xml, next >= 0 ? &known_schemas[next] : NULL)) {
|
|
crm_debug("%s-style configuration is also valid for %s",
|
|
known_schemas[lpc].name, known_schemas[next].name);
|
|
|
|
@@ -1084,7 +1082,8 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
known_schemas[lpc].transform);
|
|
rc = -pcmk_err_transform_failed;
|
|
|
|
- } else if (validate_with(upgrade, next, error_handler, GUINT_TO_POINTER(LOG_ERR))) {
|
|
+ } else if (validate_with(upgrade, next >= 0 ? &known_schemas[next] : NULL,
|
|
+ error_handler, GUINT_TO_POINTER(LOG_ERR))) {
|
|
crm_info("Transformation %s.xsl successful",
|
|
known_schemas[lpc].transform);
|
|
lpc = next;
|
|
--
|
|
2.31.1
|
|
|
|
From 26a17af650a842659f57c9e58185c290c30a3fb3 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 14:33:11 -0400
|
|
Subject: [PATCH 03/20] Refactor: libcrmcommon: Break schema freeing out into a
|
|
function.
|
|
|
|
---
|
|
lib/common/schemas.c | 69 +++++++++++++++++++++++++-------------------
|
|
1 file changed, 40 insertions(+), 29 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index f1f86f4..c21b9ae 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -511,6 +511,43 @@ validate_with_relaxng(xmlDocPtr doc, xmlRelaxNGValidityErrorFunc error_handler,
|
|
return valid;
|
|
}
|
|
|
|
+static void
|
|
+free_schema(struct schema_s *schema)
|
|
+{
|
|
+ relaxng_ctx_cache_t *ctx = NULL;
|
|
+
|
|
+ switch (schema->validator) {
|
|
+ case schema_validator_none: // not cached
|
|
+ break;
|
|
+
|
|
+ case schema_validator_rng: // cached
|
|
+ ctx = (relaxng_ctx_cache_t *) schema->cache;
|
|
+ if (ctx == NULL) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (ctx->parser != NULL) {
|
|
+ xmlRelaxNGFreeParserCtxt(ctx->parser);
|
|
+ }
|
|
+
|
|
+ if (ctx->valid != NULL) {
|
|
+ xmlRelaxNGFreeValidCtxt(ctx->valid);
|
|
+ }
|
|
+
|
|
+ if (ctx->rng != NULL) {
|
|
+ xmlRelaxNGFree(ctx->rng);
|
|
+ }
|
|
+
|
|
+ free(ctx);
|
|
+ schema->cache = NULL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ free(schema->name);
|
|
+ free(schema->transform);
|
|
+ free(schema->transform_enter);
|
|
+}
|
|
+
|
|
/*!
|
|
* \internal
|
|
* \brief Clean up global memory associated with XML schemas
|
|
@@ -518,36 +555,10 @@ validate_with_relaxng(xmlDocPtr doc, xmlRelaxNGValidityErrorFunc error_handler,
|
|
void
|
|
crm_schema_cleanup(void)
|
|
{
|
|
- int lpc;
|
|
- relaxng_ctx_cache_t *ctx = NULL;
|
|
-
|
|
- for (lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
-
|
|
- switch (known_schemas[lpc].validator) {
|
|
- case schema_validator_none: // not cached
|
|
- break;
|
|
- case schema_validator_rng: // cached
|
|
- ctx = (relaxng_ctx_cache_t *) known_schemas[lpc].cache;
|
|
- if (ctx == NULL) {
|
|
- break;
|
|
- }
|
|
- if (ctx->parser != NULL) {
|
|
- xmlRelaxNGFreeParserCtxt(ctx->parser);
|
|
- }
|
|
- if (ctx->valid != NULL) {
|
|
- xmlRelaxNGFreeValidCtxt(ctx->valid);
|
|
- }
|
|
- if (ctx->rng != NULL) {
|
|
- xmlRelaxNGFree(ctx->rng);
|
|
- }
|
|
- free(ctx);
|
|
- known_schemas[lpc].cache = NULL;
|
|
- break;
|
|
- }
|
|
- free(known_schemas[lpc].name);
|
|
- free(known_schemas[lpc].transform);
|
|
- free(known_schemas[lpc].transform_enter);
|
|
+ for (int lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
+ free_schema(&known_schemas[lpc]);
|
|
}
|
|
+
|
|
free(known_schemas);
|
|
known_schemas = NULL;
|
|
|
|
--
|
|
2.31.1
|
|
|
|
From fdf66811c23d93715fcd34e16eb58fce5f4294d7 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 14:36:07 -0400
|
|
Subject: [PATCH 04/20] Refactor: libcrmcommon: Clean up add_schema a bit.
|
|
|
|
* Use true/false instead of TRUE/FALSE.
|
|
|
|
* Call CRM_ASSERT after all the strdups.
|
|
|
|
* There's no need to have a for loop over a two element list. If the
|
|
version number struct ever changes, plenty of other places will have
|
|
to be changed as well so this isn't saving us much.
|
|
---
|
|
lib/common/schemas.c | 20 +++++++++++++-------
|
|
1 file changed, 13 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index c21b9ae..17cd21f 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -178,7 +178,7 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
int after_transform)
|
|
{
|
|
int last = xml_schema_max;
|
|
- bool have_version = FALSE;
|
|
+ bool have_version = false;
|
|
|
|
xml_schema_max++;
|
|
known_schemas = pcmk__realloc(known_schemas,
|
|
@@ -188,26 +188,32 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
known_schemas[last].validator = validator;
|
|
known_schemas[last].after_transform = after_transform;
|
|
|
|
- for (int i = 0; i < 2; ++i) {
|
|
- known_schemas[last].version.v[i] = version->v[i];
|
|
- if (version->v[i]) {
|
|
- have_version = TRUE;
|
|
- }
|
|
+ known_schemas[last].version.v[0] = version->v[0];
|
|
+ known_schemas[last].version.v[1] = version->v[1];
|
|
+
|
|
+ if (version->v[0] || version->v[1]) {
|
|
+ have_version = true;
|
|
}
|
|
+
|
|
if (have_version) {
|
|
known_schemas[last].name = schema_strdup_printf("pacemaker-", *version, "");
|
|
} else {
|
|
- CRM_ASSERT(name);
|
|
+ CRM_ASSERT(name != NULL);
|
|
schema_scanf(name, "%*[^-]-", known_schemas[last].version, "");
|
|
known_schemas[last].name = strdup(name);
|
|
+ CRM_ASSERT(known_schemas[last].name != NULL);
|
|
}
|
|
|
|
if (transform) {
|
|
known_schemas[last].transform = strdup(transform);
|
|
+ CRM_ASSERT(known_schemas[last].transform != NULL);
|
|
}
|
|
+
|
|
if (transform_enter) {
|
|
known_schemas[last].transform_enter = strdup(transform_enter);
|
|
+ CRM_ASSERT(known_schemas[last].transform_enter != NULL);
|
|
}
|
|
+
|
|
known_schemas[last].transform_onleave = transform_onleave;
|
|
if (after_transform == 0) {
|
|
after_transform = xml_schema_max; /* upgrade is a one-way */
|
|
--
|
|
2.31.1
|
|
|
|
From ef89e0536fae09036a657cf651da1eed75356054 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 15:16:11 -0400
|
|
Subject: [PATCH 05/20] Refactor: libcrmcommon: Use pcmk__s in schemas.c where
|
|
possible.
|
|
|
|
---
|
|
lib/common/schemas.c | 8 ++++----
|
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 17cd21f..fca81e4 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -1031,7 +1031,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
|
|
while (lpc <= max_stable_schemas) {
|
|
crm_debug("Testing '%s' validation (%d of %d)",
|
|
- known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>",
|
|
+ pcmk__s(known_schemas[lpc].name, "<unset>"),
|
|
lpc, max_stable_schemas);
|
|
|
|
if (validate_with(xml, &known_schemas[lpc], error_handler, GUINT_TO_POINTER(LOG_ERR)) == FALSE) {
|
|
@@ -1041,7 +1041,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
next = -1;
|
|
} else {
|
|
crm_trace("%s validation failed",
|
|
- known_schemas[lpc].name ? known_schemas[lpc].name : "<unset>");
|
|
+ pcmk__s(known_schemas[lpc].name, "<unset>"));
|
|
}
|
|
if (*best) {
|
|
/* we've satisfied the validation, no need to check further */
|
|
@@ -1128,8 +1128,8 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
|
|
if (*best > match && *best) {
|
|
crm_info("%s the configuration from %s to %s",
|
|
- transform?"Transformed":"Upgraded",
|
|
- value ? value : "<none>", known_schemas[*best].name);
|
|
+ transform?"Transformed":"Upgraded", pcmk__s(value, "<none>"),
|
|
+ known_schemas[*best].name);
|
|
crm_xml_add(xml, XML_ATTR_VALIDATION, known_schemas[*best].name);
|
|
}
|
|
|
|
--
|
|
2.31.1
|
|
|
|
From 574c3c1f5ca00514eff77b927821b695c980a683 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 15:20:04 -0400
|
|
Subject: [PATCH 06/20] Refactor: libcrmcommon: Use a schema variable in
|
|
update_validation.
|
|
|
|
This just gets rid of a ton of references to the known_schemas array,
|
|
making it easier to replace that array with something else in a future
|
|
commit.
|
|
---
|
|
lib/common/schemas.c | 38 +++++++++++++++++---------------------
|
|
1 file changed, 17 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index fca81e4..888a473 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -1030,18 +1030,18 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
}
|
|
|
|
while (lpc <= max_stable_schemas) {
|
|
+ struct schema_s *schema = &known_schemas[lpc];
|
|
+
|
|
crm_debug("Testing '%s' validation (%d of %d)",
|
|
- pcmk__s(known_schemas[lpc].name, "<unset>"),
|
|
- lpc, max_stable_schemas);
|
|
+ pcmk__s(schema->name, "<unset>"), lpc, max_stable_schemas);
|
|
|
|
- if (validate_with(xml, &known_schemas[lpc], error_handler, GUINT_TO_POINTER(LOG_ERR)) == FALSE) {
|
|
+ if (validate_with(xml, schema, error_handler, GUINT_TO_POINTER(LOG_ERR)) == FALSE) {
|
|
if (next != -1) {
|
|
crm_info("Configuration not valid for schema: %s",
|
|
- known_schemas[lpc].name);
|
|
+ schema->name);
|
|
next = -1;
|
|
} else {
|
|
- crm_trace("%s validation failed",
|
|
- pcmk__s(known_schemas[lpc].name, "<unset>"));
|
|
+ crm_trace("%s validation failed", pcmk__s(schema->name, "<unset>"));
|
|
}
|
|
if (*best) {
|
|
/* we've satisfied the validation, no need to check further */
|
|
@@ -1051,8 +1051,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
|
|
} else {
|
|
if (next != -1) {
|
|
- crm_debug("Configuration valid for schema: %s",
|
|
- known_schemas[next].name);
|
|
+ crm_debug("Configuration valid for schema: %s", schema->name);
|
|
next = -1;
|
|
}
|
|
rc = pcmk_ok;
|
|
@@ -1064,19 +1063,19 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
|
|
if (rc == pcmk_ok && transform) {
|
|
xmlNode *upgrade = NULL;
|
|
- next = known_schemas[lpc].after_transform;
|
|
+ next = schema->after_transform;
|
|
|
|
if (next <= lpc) {
|
|
/* There is no next version, or next would regress */
|
|
- crm_trace("Stopping at %s", known_schemas[lpc].name);
|
|
+ crm_trace("Stopping at %s", schema->name);
|
|
break;
|
|
|
|
} else if (max > 0 && (lpc == max || next > max)) {
|
|
crm_trace("Upgrade limit reached at %s (lpc=%d, next=%d, max=%d)",
|
|
- known_schemas[lpc].name, lpc, next, max);
|
|
+ schema->name, lpc, next, max);
|
|
break;
|
|
|
|
- } else if (known_schemas[lpc].transform == NULL
|
|
+ } else if (schema->transform == NULL
|
|
/* possibly avoid transforming when readily valid
|
|
(in general more restricted when crossing the major
|
|
version boundary, as X.0 "transitional" version is
|
|
@@ -1084,25 +1083,22 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
may re-allow constructs from previous major line) */
|
|
|| validate_with_silent(xml, next >= 0 ? &known_schemas[next] : NULL)) {
|
|
crm_debug("%s-style configuration is also valid for %s",
|
|
- known_schemas[lpc].name, known_schemas[next].name);
|
|
+ schema->name, known_schemas[next].name);
|
|
|
|
lpc = next;
|
|
|
|
} else {
|
|
crm_debug("Upgrading %s-style configuration to %s with %s.xsl",
|
|
- known_schemas[lpc].name, known_schemas[next].name,
|
|
- known_schemas[lpc].transform);
|
|
+ schema->name, known_schemas[next].name, schema->transform);
|
|
|
|
- upgrade = apply_upgrade(xml, &known_schemas[lpc], to_logs);
|
|
+ upgrade = apply_upgrade(xml, schema, to_logs);
|
|
if (upgrade == NULL) {
|
|
- crm_err("Transformation %s.xsl failed",
|
|
- known_schemas[lpc].transform);
|
|
+ crm_err("Transformation %s.xsl failed", schema->transform);
|
|
rc = -pcmk_err_transform_failed;
|
|
|
|
} else if (validate_with(upgrade, next >= 0 ? &known_schemas[next] : NULL,
|
|
error_handler, GUINT_TO_POINTER(LOG_ERR))) {
|
|
- crm_info("Transformation %s.xsl successful",
|
|
- known_schemas[lpc].transform);
|
|
+ crm_info("Transformation %s.xsl successful", schema->transform);
|
|
lpc = next;
|
|
*best = next;
|
|
free_xml(xml);
|
|
@@ -1111,7 +1107,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
|
|
} else {
|
|
crm_err("Transformation %s.xsl did not produce a valid configuration",
|
|
- known_schemas[lpc].transform);
|
|
+ schema->transform);
|
|
crm_log_xml_info(upgrade, "transform:bad");
|
|
free_xml(upgrade);
|
|
rc = -pcmk_err_schema_validation;
|
|
--
|
|
2.31.1
|
|
|
|
From dc724c940014fbe60aa506d8acb652b2dd5dce90 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 15:31:27 -0400
|
|
Subject: [PATCH 07/20] Refactor: libcrmcommon: Use a variable for the next
|
|
schema, too.
|
|
|
|
This gets rid of further references to known_schemas update_validation,
|
|
also with the purpose of making it easier to change the implementation
|
|
of that array.
|
|
---
|
|
lib/common/schemas.c | 20 +++++++++++++-------
|
|
1 file changed, 13 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 888a473..8e5c22e 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -1063,41 +1063,47 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
|
|
if (rc == pcmk_ok && transform) {
|
|
xmlNode *upgrade = NULL;
|
|
+ struct schema_s *next_schema = NULL;
|
|
next = schema->after_transform;
|
|
|
|
if (next <= lpc) {
|
|
/* There is no next version, or next would regress */
|
|
crm_trace("Stopping at %s", schema->name);
|
|
break;
|
|
+ }
|
|
|
|
- } else if (max > 0 && (lpc == max || next > max)) {
|
|
+ if (max > 0 && (lpc == max || next > max)) {
|
|
crm_trace("Upgrade limit reached at %s (lpc=%d, next=%d, max=%d)",
|
|
schema->name, lpc, next, max);
|
|
break;
|
|
+ }
|
|
+
|
|
+ next_schema = &known_schemas[next];
|
|
+ CRM_ASSERT(next_schema != NULL);
|
|
|
|
- } else if (schema->transform == NULL
|
|
+ if (schema->transform == NULL
|
|
/* possibly avoid transforming when readily valid
|
|
(in general more restricted when crossing the major
|
|
version boundary, as X.0 "transitional" version is
|
|
expected to be more strict than it's successors that
|
|
may re-allow constructs from previous major line) */
|
|
- || validate_with_silent(xml, next >= 0 ? &known_schemas[next] : NULL)) {
|
|
+ || validate_with_silent(xml, next_schema)) {
|
|
crm_debug("%s-style configuration is also valid for %s",
|
|
- schema->name, known_schemas[next].name);
|
|
+ schema->name, next_schema->name);
|
|
|
|
lpc = next;
|
|
|
|
} else {
|
|
crm_debug("Upgrading %s-style configuration to %s with %s.xsl",
|
|
- schema->name, known_schemas[next].name, schema->transform);
|
|
+ schema->name, next_schema->name, schema->transform);
|
|
|
|
upgrade = apply_upgrade(xml, schema, to_logs);
|
|
if (upgrade == NULL) {
|
|
crm_err("Transformation %s.xsl failed", schema->transform);
|
|
rc = -pcmk_err_transform_failed;
|
|
|
|
- } else if (validate_with(upgrade, next >= 0 ? &known_schemas[next] : NULL,
|
|
- error_handler, GUINT_TO_POINTER(LOG_ERR))) {
|
|
+ } else if (validate_with(upgrade, next_schema, error_handler,
|
|
+ GUINT_TO_POINTER(LOG_ERR))) {
|
|
crm_info("Transformation %s.xsl successful", schema->transform);
|
|
lpc = next;
|
|
*best = next;
|
|
--
|
|
2.31.1
|
|
|
|
From 0664f7e327c612d5602515ecf4bb32fb7c3503f6 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 16:09:30 -0400
|
|
Subject: [PATCH 08/20] Refactor: libcrmcommon: Add pcmk__dump_known_schemas.
|
|
|
|
The debug logging in add_schema isn't necessarily all that useful.
|
|
Typically, schema adding happens in crm_log_preinit which means it
|
|
happens before logging is set up, so nothing that we log actually goes
|
|
anywhere.
|
|
|
|
This function does the same thing but can be called where needed.
|
|
---
|
|
include/crm/common/xml_internal.h | 3 +++
|
|
lib/common/schemas.c | 21 +++++++++++++++++++++
|
|
2 files changed, 24 insertions(+)
|
|
|
|
diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h
|
|
index ddb4384..f319856 100644
|
|
--- a/include/crm/common/xml_internal.h
|
|
+++ b/include/crm/common/xml_internal.h
|
|
@@ -441,8 +441,11 @@ pcmk__xml_attr_value(const xmlAttr *attr)
|
|
: (const char *) attr->children->content;
|
|
}
|
|
|
|
+
|
|
gboolean pcmk__validate_xml(xmlNode *xml_blob, const char *validation,
|
|
xmlRelaxNGValidityErrorFunc error_handler,
|
|
void *error_handler_context);
|
|
|
|
+void pcmk__log_known_schemas(void);
|
|
+
|
|
#endif // PCMK__XML_INTERNAL__H
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 8e5c22e..41ca138 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -1248,3 +1248,24 @@ cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
|
|
free(orig_value);
|
|
return rc;
|
|
}
|
|
+
|
|
+void
|
|
+pcmk__log_known_schemas(void)
|
|
+{
|
|
+ for (int lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
+ if (known_schemas[lpc].after_transform < 0) {
|
|
+ crm_debug("known_schemas[%d] => %s", lpc, known_schemas[lpc].name);
|
|
+
|
|
+ } else if (known_schemas[lpc].transform != NULL) {
|
|
+ crm_debug("known_schemas[%d] => %s (upgrades to %d with %s.xsl)",
|
|
+ lpc, known_schemas[lpc].name,
|
|
+ known_schemas[lpc].after_transform,
|
|
+ known_schemas[lpc].transform);
|
|
+
|
|
+ } else {
|
|
+ crm_debug("known_schemas[%d] => %s (upgrades to %d)",
|
|
+ lpc, known_schemas[lpc].name,
|
|
+ known_schemas[lpc].after_transform);
|
|
+ }
|
|
+ }
|
|
+}
|
|
--
|
|
2.31.1
|
|
|
|
From 423a28fd5c2b71945d75b68b168a607279d795f7 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 17:22:53 -0400
|
|
Subject: [PATCH 09/20] Refactor: libcrmcommon: Store known_schemas as a GList.
|
|
|
|
Instead of managing our own array with realloc, use GList and the
|
|
various glib list functions.
|
|
|
|
In many places, this makes the code easier to follow - we can simply
|
|
iterate over the list and do something on each node. In other places,
|
|
we're still relying on list indices too much to help. Those spots can
|
|
probably be cleaned up in future commits.
|
|
---
|
|
lib/common/schemas.c | 181 ++++++++++++++++++++++++++-----------------
|
|
1 file changed, 108 insertions(+), 73 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 41ca138..6e6f32e 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -60,7 +60,7 @@ struct schema_s {
|
|
bool transform_onleave;
|
|
};
|
|
|
|
-static struct schema_s *known_schemas = NULL;
|
|
+static GList *known_schemas = NULL;
|
|
static int xml_schema_max = 0;
|
|
static bool silent_logging = FALSE;
|
|
|
|
@@ -81,27 +81,45 @@ static int
|
|
xml_latest_schema_index(void)
|
|
{
|
|
// @COMPAT: pacemaker-next is deprecated since 2.1.5
|
|
- return xml_schema_max - 3; // index from 0, ignore "pacemaker-next"/"none"
|
|
+ // FIXME: This function assumes at least three schemas have been added
|
|
+ // before it has been called for the first time.
|
|
+ return g_list_length(known_schemas) - 3; // index from 0, ignore "pacemaker-next"/"none"
|
|
}
|
|
|
|
static int
|
|
xml_minimum_schema_index(void)
|
|
{
|
|
static int best = 0;
|
|
- if (best == 0) {
|
|
- int lpc = 0;
|
|
-
|
|
- best = xml_latest_schema_index();
|
|
- for (lpc = best; lpc > 0; lpc--) {
|
|
- if (known_schemas[lpc].version.v[0]
|
|
- < known_schemas[best].version.v[0]) {
|
|
- return best;
|
|
- } else {
|
|
- best = lpc;
|
|
- }
|
|
+ struct schema_s *best_schema = NULL;
|
|
+ GList *last_real_ele = NULL;
|
|
+
|
|
+ if (best != 0) {
|
|
+ return best;
|
|
+ }
|
|
+
|
|
+ best = xml_latest_schema_index();
|
|
+
|
|
+ /* We can't just use g_list_last here because "pacemaker-next" and "none"
|
|
+ * are stored at the end of the list. We need to start several elements
|
|
+ * back, at the last real schema.
|
|
+ */
|
|
+ last_real_ele = g_list_nth(known_schemas, best);
|
|
+ best_schema = last_real_ele->data;
|
|
+
|
|
+ for (GList *iter = last_real_ele; iter != NULL; iter = iter->prev) {
|
|
+ struct schema_s *schema = iter->data;
|
|
+
|
|
+ if (schema->version.v[0] < best_schema->version.v[0]) {
|
|
+ return best;
|
|
+ } else {
|
|
+ best--;
|
|
}
|
|
- best = xml_latest_schema_index();
|
|
}
|
|
+
|
|
+ /* If we never found a schema that meets the above criteria, default to
|
|
+ * the last one.
|
|
+ */
|
|
+ best = xml_latest_schema_index();
|
|
return best;
|
|
}
|
|
|
|
@@ -177,63 +195,61 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
const char *transform_enter, bool transform_onleave,
|
|
int after_transform)
|
|
{
|
|
+ struct schema_s *schema = NULL;
|
|
int last = xml_schema_max;
|
|
bool have_version = false;
|
|
|
|
xml_schema_max++;
|
|
- known_schemas = pcmk__realloc(known_schemas,
|
|
- xml_schema_max * sizeof(struct schema_s));
|
|
- CRM_ASSERT(known_schemas != NULL);
|
|
- memset(known_schemas+last, 0, sizeof(struct schema_s));
|
|
- known_schemas[last].validator = validator;
|
|
- known_schemas[last].after_transform = after_transform;
|
|
|
|
- known_schemas[last].version.v[0] = version->v[0];
|
|
- known_schemas[last].version.v[1] = version->v[1];
|
|
+ schema = calloc(1, sizeof(struct schema_s));
|
|
+ CRM_ASSERT(schema != NULL);
|
|
+
|
|
+ schema->validator = validator;
|
|
+ schema->after_transform = after_transform;
|
|
+ schema->version.v[0] = version->v[0];
|
|
+ schema->version.v[1] = version->v[1];
|
|
|
|
if (version->v[0] || version->v[1]) {
|
|
have_version = true;
|
|
}
|
|
|
|
if (have_version) {
|
|
- known_schemas[last].name = schema_strdup_printf("pacemaker-", *version, "");
|
|
+ schema->name = schema_strdup_printf("pacemaker-", *version, "");
|
|
} else {
|
|
CRM_ASSERT(name != NULL);
|
|
- schema_scanf(name, "%*[^-]-", known_schemas[last].version, "");
|
|
- known_schemas[last].name = strdup(name);
|
|
- CRM_ASSERT(known_schemas[last].name != NULL);
|
|
+ schema_scanf(name, "%*[^-]-", schema->version, "");
|
|
+ schema->name = strdup(name);
|
|
+ CRM_ASSERT(schema->name != NULL);
|
|
}
|
|
|
|
if (transform) {
|
|
- known_schemas[last].transform = strdup(transform);
|
|
- CRM_ASSERT(known_schemas[last].transform != NULL);
|
|
+ schema->transform = strdup(transform);
|
|
+ CRM_ASSERT(schema->transform != NULL);
|
|
}
|
|
|
|
if (transform_enter) {
|
|
- known_schemas[last].transform_enter = strdup(transform_enter);
|
|
- CRM_ASSERT(known_schemas[last].transform_enter != NULL);
|
|
+ schema->transform_enter = strdup(transform_enter);
|
|
+ CRM_ASSERT(schema->transform_enter != NULL);
|
|
}
|
|
|
|
- known_schemas[last].transform_onleave = transform_onleave;
|
|
+ schema->transform_onleave = transform_onleave;
|
|
if (after_transform == 0) {
|
|
after_transform = xml_schema_max; /* upgrade is a one-way */
|
|
}
|
|
- known_schemas[last].after_transform = after_transform;
|
|
+ schema->after_transform = after_transform;
|
|
|
|
- if (known_schemas[last].after_transform < 0) {
|
|
- crm_debug("Added supported schema %d: %s",
|
|
- last, known_schemas[last].name);
|
|
+ known_schemas = g_list_append(known_schemas, schema);
|
|
|
|
- } else if (known_schemas[last].transform) {
|
|
+ if (schema->after_transform < 0) {
|
|
+ crm_debug("Added supported schema %d: %s", last, schema->name);
|
|
+
|
|
+ } else if (schema->transform != NULL) {
|
|
crm_debug("Added supported schema %d: %s (upgrades to %d with %s.xsl)",
|
|
- last, known_schemas[last].name,
|
|
- known_schemas[last].after_transform,
|
|
- known_schemas[last].transform);
|
|
+ last, schema->name, schema->after_transform, schema->transform);
|
|
|
|
} else {
|
|
crm_debug("Added supported schema %d: %s (upgrades to %d)",
|
|
- last, known_schemas[last].name,
|
|
- known_schemas[last].after_transform);
|
|
+ last, schema->name, schema->after_transform);
|
|
}
|
|
}
|
|
|
|
@@ -518,8 +534,9 @@ validate_with_relaxng(xmlDocPtr doc, xmlRelaxNGValidityErrorFunc error_handler,
|
|
}
|
|
|
|
static void
|
|
-free_schema(struct schema_s *schema)
|
|
+free_schema(gpointer data)
|
|
{
|
|
+ struct schema_s *schema = data;
|
|
relaxng_ctx_cache_t *ctx = NULL;
|
|
|
|
switch (schema->validator) {
|
|
@@ -561,11 +578,7 @@ free_schema(struct schema_s *schema)
|
|
void
|
|
crm_schema_cleanup(void)
|
|
{
|
|
- for (int lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
- free_schema(&known_schemas[lpc]);
|
|
- }
|
|
-
|
|
- free(known_schemas);
|
|
+ g_list_free_full(known_schemas, free_schema);
|
|
known_schemas = NULL;
|
|
|
|
wrap_libxslt(true);
|
|
@@ -697,16 +710,17 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
}
|
|
|
|
if (validation == NULL) {
|
|
- int lpc = 0;
|
|
bool valid = FALSE;
|
|
|
|
- for (lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
- if (validate_with(xml_blob, &known_schemas[lpc], NULL, NULL)) {
|
|
+ for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
+ struct schema_s *schema = iter->data;
|
|
+
|
|
+ if (validate_with(xml_blob, schema, NULL, NULL)) {
|
|
valid = TRUE;
|
|
- crm_xml_add(xml_blob, XML_ATTR_VALIDATION,
|
|
- known_schemas[lpc].name);
|
|
- crm_info("XML validated against %s", known_schemas[lpc].name);
|
|
- if(known_schemas[lpc].after_transform == 0) {
|
|
+ crm_xml_add(xml_blob, XML_ATTR_VALIDATION, schema->name);
|
|
+ crm_info("XML validated against %s", schema->name);
|
|
+
|
|
+ if (schema->after_transform == 0) {
|
|
break;
|
|
}
|
|
}
|
|
@@ -719,8 +733,9 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
if (strcmp(validation, PCMK__VALUE_NONE) == 0) {
|
|
return TRUE;
|
|
} else if (version < xml_schema_max) {
|
|
- return validate_with(xml_blob, version >= 0 ? &known_schemas[version] : NULL,
|
|
- error_handler, error_handler_context);
|
|
+ struct schema_s *schema = g_list_nth_data(known_schemas, version);
|
|
+ return validate_with(xml_blob, schema, error_handler,
|
|
+ error_handler_context);
|
|
}
|
|
|
|
crm_err("Unknown validator: %s", validation);
|
|
@@ -964,10 +979,13 @@ apply_upgrade(xmlNode *xml, const struct schema_s *schema, gboolean to_logs)
|
|
const char *
|
|
get_schema_name(int version)
|
|
{
|
|
- if (version < 0 || version >= xml_schema_max) {
|
|
+ struct schema_s *schema = g_list_nth_data(known_schemas, version);
|
|
+
|
|
+ if (schema == NULL) {
|
|
return "unknown";
|
|
}
|
|
- return known_schemas[version].name;
|
|
+
|
|
+ return schema->name;
|
|
}
|
|
|
|
int
|
|
@@ -978,11 +996,17 @@ get_schema_version(const char *name)
|
|
if (name == NULL) {
|
|
name = PCMK__VALUE_NONE;
|
|
}
|
|
- for (; lpc < xml_schema_max; lpc++) {
|
|
- if (pcmk__str_eq(name, known_schemas[lpc].name, pcmk__str_casei)) {
|
|
+
|
|
+ for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
+ struct schema_s *schema = iter->data;
|
|
+
|
|
+ if (pcmk__str_eq(name, schema->name, pcmk__str_casei)) {
|
|
return lpc;
|
|
}
|
|
+
|
|
+ lpc++;
|
|
}
|
|
+
|
|
return -1;
|
|
}
|
|
|
|
@@ -1030,7 +1054,12 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
}
|
|
|
|
while (lpc <= max_stable_schemas) {
|
|
- struct schema_s *schema = &known_schemas[lpc];
|
|
+ /* FIXME: This will cause us to walk the known_schemas list every time
|
|
+ * this loop iterates, which is not ideal. However, for now it's a lot
|
|
+ * easier than trying to get all the loop indices we're using here
|
|
+ * sorted out and working correctly.
|
|
+ */
|
|
+ struct schema_s *schema = g_list_nth_data(known_schemas, lpc);
|
|
|
|
crm_debug("Testing '%s' validation (%d of %d)",
|
|
pcmk__s(schema->name, "<unset>"), lpc, max_stable_schemas);
|
|
@@ -1078,7 +1107,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
break;
|
|
}
|
|
|
|
- next_schema = &known_schemas[next];
|
|
+ next_schema = g_list_nth_data(known_schemas, next);
|
|
CRM_ASSERT(next_schema != NULL);
|
|
|
|
if (schema->transform == NULL
|
|
@@ -1129,10 +1158,12 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
}
|
|
|
|
if (*best > match && *best) {
|
|
+ struct schema_s *best_schema = g_list_nth_data(known_schemas, *best);
|
|
+
|
|
crm_info("%s the configuration from %s to %s",
|
|
transform?"Transformed":"Upgraded", pcmk__s(value, "<none>"),
|
|
- known_schemas[*best].name);
|
|
- crm_xml_add(xml, XML_ATTR_VALIDATION, known_schemas[*best].name);
|
|
+ best_schema->name);
|
|
+ crm_xml_add(xml, XML_ATTR_VALIDATION, best_schema->name);
|
|
}
|
|
|
|
*xml_blob = xml;
|
|
@@ -1252,20 +1283,24 @@ cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
|
|
void
|
|
pcmk__log_known_schemas(void)
|
|
{
|
|
- for (int lpc = 0; lpc < xml_schema_max; lpc++) {
|
|
- if (known_schemas[lpc].after_transform < 0) {
|
|
- crm_debug("known_schemas[%d] => %s", lpc, known_schemas[lpc].name);
|
|
+ int lpc = 0;
|
|
|
|
- } else if (known_schemas[lpc].transform != NULL) {
|
|
+ for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
+ struct schema_s *schema = iter->data;
|
|
+
|
|
+ if (schema->after_transform < 0) {
|
|
+ crm_debug("known_schemas[%d] => %s", lpc, schema->name);
|
|
+
|
|
+ } else if (schema->transform != NULL) {
|
|
crm_debug("known_schemas[%d] => %s (upgrades to %d with %s.xsl)",
|
|
- lpc, known_schemas[lpc].name,
|
|
- known_schemas[lpc].after_transform,
|
|
- known_schemas[lpc].transform);
|
|
+ lpc, schema->name, schema->after_transform,
|
|
+ schema->transform);
|
|
|
|
} else {
|
|
crm_debug("known_schemas[%d] => %s (upgrades to %d)",
|
|
- lpc, known_schemas[lpc].name,
|
|
- known_schemas[lpc].after_transform);
|
|
+ lpc, schema->name, schema->after_transform);
|
|
}
|
|
+
|
|
+ lpc++;
|
|
}
|
|
}
|
|
--
|
|
2.31.1
|
|
|
|
From 33cfcc0d98603e04dde15d69acd46823679405f0 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Wed, 25 Oct 2023 17:34:25 -0400
|
|
Subject: [PATCH 10/20] Refactor: libcrmcommon: Get rid of xml_schema_max.
|
|
|
|
This is just the length of the known_schemas list.
|
|
---
|
|
lib/common/schemas.c | 9 +++------
|
|
1 file changed, 3 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 6e6f32e..d4ce68e 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -61,7 +61,6 @@ struct schema_s {
|
|
};
|
|
|
|
static GList *known_schemas = NULL;
|
|
-static int xml_schema_max = 0;
|
|
static bool silent_logging = FALSE;
|
|
|
|
static void G_GNUC_PRINTF(2, 3)
|
|
@@ -196,11 +195,9 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
int after_transform)
|
|
{
|
|
struct schema_s *schema = NULL;
|
|
- int last = xml_schema_max;
|
|
+ int last = g_list_length(known_schemas);
|
|
bool have_version = false;
|
|
|
|
- xml_schema_max++;
|
|
-
|
|
schema = calloc(1, sizeof(struct schema_s));
|
|
CRM_ASSERT(schema != NULL);
|
|
|
|
@@ -234,7 +231,7 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
|
|
schema->transform_onleave = transform_onleave;
|
|
if (after_transform == 0) {
|
|
- after_transform = xml_schema_max; /* upgrade is a one-way */
|
|
+ after_transform = last + 1; /* upgrade is a one-way */
|
|
}
|
|
schema->after_transform = after_transform;
|
|
|
|
@@ -732,7 +729,7 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
version = get_schema_version(validation);
|
|
if (strcmp(validation, PCMK__VALUE_NONE) == 0) {
|
|
return TRUE;
|
|
- } else if (version < xml_schema_max) {
|
|
+ } else if (version < g_list_length(known_schemas)) {
|
|
struct schema_s *schema = g_list_nth_data(known_schemas, version);
|
|
return validate_with(xml_blob, schema, error_handler,
|
|
error_handler_context);
|
|
--
|
|
2.31.1
|
|
|
|
From 6ace4c912d34f495ab5f52500628c82fb1533256 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Thu, 26 Oct 2023 12:52:14 -0400
|
|
Subject: [PATCH 11/20] Refactor: libcrmcommon: Rename
|
|
xml_minimum_schema_index.
|
|
|
|
This function's name is unclear. It actually returns the most recent
|
|
X.0 schema index. The new name is pretty bad, but I think it's at least
|
|
clear.
|
|
|
|
And then while I'm at it, rewrite it to make it more clear. Just
|
|
iterate the known_schemas list, looking for the right .0 one. This code
|
|
does not get run very often, and it caches its result, so there's no
|
|
need to do the reverse traversal with a lagging index.
|
|
---
|
|
lib/common/schemas.c | 41 +++++++++++++++++++++++++----------------
|
|
1 file changed, 25 insertions(+), 16 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index d4ce68e..55519e8 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -85,39 +85,48 @@ xml_latest_schema_index(void)
|
|
return g_list_length(known_schemas) - 3; // index from 0, ignore "pacemaker-next"/"none"
|
|
}
|
|
|
|
+/* Return the index of the most recent X.0 schema. */
|
|
static int
|
|
-xml_minimum_schema_index(void)
|
|
+xml_find_x_0_schema_index(void)
|
|
{
|
|
static int best = 0;
|
|
+ int i = 0;
|
|
struct schema_s *best_schema = NULL;
|
|
- GList *last_real_ele = NULL;
|
|
|
|
if (best != 0) {
|
|
return best;
|
|
}
|
|
|
|
+ /* Get the most recent schema so we can look at its version number. */
|
|
best = xml_latest_schema_index();
|
|
+ best_schema = g_list_nth(known_schemas, best)->data;
|
|
|
|
- /* We can't just use g_list_last here because "pacemaker-next" and "none"
|
|
- * are stored at the end of the list. We need to start several elements
|
|
- * back, at the last real schema.
|
|
+ /* Iterate over the schema list until we find a schema with the same major
|
|
+ * version as best, and with a minor version number of 0.
|
|
+ *
|
|
+ * This assumes that the first schema in a major series is always X.0,
|
|
+ * which seems like a safe assumption.
|
|
*/
|
|
- last_real_ele = g_list_nth(known_schemas, best);
|
|
- best_schema = last_real_ele->data;
|
|
-
|
|
- for (GList *iter = last_real_ele; iter != NULL; iter = iter->prev) {
|
|
+ for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
struct schema_s *schema = iter->data;
|
|
|
|
- if (schema->version.v[0] < best_schema->version.v[0]) {
|
|
+ /* If we hit the initial best schema, the only things left in the list
|
|
+ * are "pacemaker-next" and "none" which aren't worth checking.
|
|
+ */
|
|
+ if (schema == best_schema) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (schema->version.v[0] == best_schema->version.v[0] &&
|
|
+ schema->version.v[1] == 0) {
|
|
+ best = i;
|
|
return best;
|
|
- } else {
|
|
- best--;
|
|
}
|
|
+
|
|
+ i++;
|
|
}
|
|
|
|
- /* If we never found a schema that meets the above criteria, default to
|
|
- * the last one.
|
|
- */
|
|
+ /* If we got here, we never found a match. Just return the latest. */
|
|
best = xml_latest_schema_index();
|
|
return best;
|
|
}
|
|
@@ -1177,7 +1186,7 @@ cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
|
|
|
|
int version = get_schema_version(value);
|
|
int orig_version = version;
|
|
- int min_version = xml_minimum_schema_index();
|
|
+ int min_version = xml_find_x_0_schema_index();
|
|
|
|
if (version < min_version) {
|
|
// Current configuration schema is not acceptable, try to update
|
|
--
|
|
2.31.1
|
|
|
|
From 7df1d2df9e8710183735b19947a885bb129e523e Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Thu, 26 Oct 2023 14:14:02 -0400
|
|
Subject: [PATCH 12/20] Refactor: libcrmcommon: Remove an unnecessary check in
|
|
validate_xml.
|
|
|
|
I believe that add_schema ensures after_transform is never 0 - it's
|
|
either negative, or some positive non-zero value. So this check should
|
|
be pointless.
|
|
---
|
|
lib/common/schemas.c | 4 ----
|
|
1 file changed, 4 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 55519e8..cfb83dd 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -725,10 +725,6 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
valid = TRUE;
|
|
crm_xml_add(xml_blob, XML_ATTR_VALIDATION, schema->name);
|
|
crm_info("XML validated against %s", schema->name);
|
|
-
|
|
- if (schema->after_transform == 0) {
|
|
- break;
|
|
- }
|
|
}
|
|
}
|
|
|
|
--
|
|
2.31.1
|
|
|
|
From dbf94f5a3c146992fb60c231a7eda21271b62b99 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Fri, 27 Oct 2023 10:49:49 -0400
|
|
Subject: [PATCH 13/20] Refactor: libcrmcommon: Change how schema upgrade
|
|
versions are handled
|
|
|
|
...in update_validation. Schemas always either upgrade to the next one
|
|
in the list, or do not upgrade. The latter only happens when we get to
|
|
the last real version and the next one is pacemaker-next/none.
|
|
|
|
With that change made, we also need to change the conditional. There's
|
|
no need to check that the upgrade will regress. We only need to check
|
|
that we've run off the end of the list of real schema versions.
|
|
|
|
A future commit will remove the after_transform variable entirely, but
|
|
since this is its most visible and complicated use, splitting this into
|
|
a separate commit seems worth it.
|
|
---
|
|
lib/common/schemas.c | 6 +++---
|
|
1 file changed, 3 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index cfb83dd..3ebdf1c 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -1095,10 +1095,10 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
if (rc == pcmk_ok && transform) {
|
|
xmlNode *upgrade = NULL;
|
|
struct schema_s *next_schema = NULL;
|
|
- next = schema->after_transform;
|
|
+ next = lpc+1;
|
|
|
|
- if (next <= lpc) {
|
|
- /* There is no next version, or next would regress */
|
|
+ if (next > max_stable_schemas) {
|
|
+ /* There is no next version */
|
|
crm_trace("Stopping at %s", schema->name);
|
|
break;
|
|
}
|
|
--
|
|
2.31.1
|
|
|
|
From b2da7aaba5a1afe9d4f56989c0b81dd55abaf1b8 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Fri, 27 Oct 2023 11:00:12 -0400
|
|
Subject: [PATCH 14/20] Refactor: libcrmcommon: Get rid of after_transform.
|
|
|
|
As stated in the previous commit, schemas always just upgrade to the
|
|
next one in the list. There's no need to keep track of that fact, so
|
|
get rid of the variable that held it. This then allows us to get rid of
|
|
all the places that value was being set and passed around.
|
|
---
|
|
lib/common/schemas.c | 54 +++++++++++++-------------------------------
|
|
1 file changed, 16 insertions(+), 38 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 3ebdf1c..e33d3c7 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -54,7 +54,6 @@ struct schema_s {
|
|
char *transform;
|
|
void *cache;
|
|
enum schema_validator_e validator;
|
|
- int after_transform;
|
|
schema_version_t version;
|
|
char *transform_enter;
|
|
bool transform_onleave;
|
|
@@ -200,8 +199,7 @@ schema_sort(const struct dirent **a, const struct dirent **b)
|
|
static void
|
|
add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
const char *name, const char *transform,
|
|
- const char *transform_enter, bool transform_onleave,
|
|
- int after_transform)
|
|
+ const char *transform_enter, bool transform_onleave)
|
|
{
|
|
struct schema_s *schema = NULL;
|
|
int last = g_list_length(known_schemas);
|
|
@@ -211,9 +209,9 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
CRM_ASSERT(schema != NULL);
|
|
|
|
schema->validator = validator;
|
|
- schema->after_transform = after_transform;
|
|
schema->version.v[0] = version->v[0];
|
|
schema->version.v[1] = version->v[1];
|
|
+ schema->transform_onleave = transform_onleave;
|
|
|
|
if (version->v[0] || version->v[1]) {
|
|
have_version = true;
|
|
@@ -238,24 +236,14 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
CRM_ASSERT(schema->transform_enter != NULL);
|
|
}
|
|
|
|
- schema->transform_onleave = transform_onleave;
|
|
- if (after_transform == 0) {
|
|
- after_transform = last + 1; /* upgrade is a one-way */
|
|
- }
|
|
- schema->after_transform = after_transform;
|
|
-
|
|
known_schemas = g_list_append(known_schemas, schema);
|
|
|
|
- if (schema->after_transform < 0) {
|
|
- crm_debug("Added supported schema %d: %s", last, schema->name);
|
|
-
|
|
- } else if (schema->transform != NULL) {
|
|
- crm_debug("Added supported schema %d: %s (upgrades to %d with %s.xsl)",
|
|
- last, schema->name, schema->after_transform, schema->transform);
|
|
+ if (schema->transform != NULL) {
|
|
+ crm_debug("Added supported schema %d: %s (upgrades with %s.xsl)",
|
|
+ last, schema->name, schema->transform);
|
|
|
|
} else {
|
|
- crm_debug("Added supported schema %d: %s (upgrades to %d)",
|
|
- last, schema->name, schema->after_transform);
|
|
+ crm_debug("Added supported schema %d: %s", last, schema->name);
|
|
}
|
|
}
|
|
|
|
@@ -288,8 +276,7 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
* . name convention: (see "upgrade-enter")
|
|
*/
|
|
static int
|
|
-add_schema_by_version(const schema_version_t *version, int next,
|
|
- bool transform_expected)
|
|
+add_schema_by_version(const schema_version_t *version, bool transform_expected)
|
|
{
|
|
bool transform_onleave = FALSE;
|
|
int rc = pcmk_rc_ok;
|
|
@@ -345,12 +332,11 @@ add_schema_by_version(const schema_version_t *version, int next,
|
|
free(xslt);
|
|
free(transform_upgrade);
|
|
transform_upgrade = NULL;
|
|
- next = -1;
|
|
rc = ENOENT;
|
|
}
|
|
|
|
add_schema(schema_validator_rng, version, NULL,
|
|
- transform_upgrade, transform_enter, transform_onleave, next);
|
|
+ transform_upgrade, transform_enter, transform_onleave);
|
|
|
|
free(transform_upgrade);
|
|
free(transform_enter);
|
|
@@ -416,7 +402,6 @@ crm_schema_init(void)
|
|
free(base);
|
|
for (lpc = 0; lpc < max; lpc++) {
|
|
bool transform_expected = FALSE;
|
|
- int next = 0;
|
|
schema_version_t version = SCHEMA_ZERO;
|
|
|
|
if (!version_from_filename(namelist[lpc]->d_name, &version)) {
|
|
@@ -432,11 +417,9 @@ crm_schema_init(void)
|
|
&& (version.v[0] < next_version.v[0])) {
|
|
transform_expected = TRUE;
|
|
}
|
|
-
|
|
- } else {
|
|
- next = -1;
|
|
}
|
|
- if (add_schema_by_version(&version, next, transform_expected)
|
|
+
|
|
+ if (add_schema_by_version(&version, transform_expected)
|
|
== ENOENT) {
|
|
break;
|
|
}
|
|
@@ -450,10 +433,10 @@ crm_schema_init(void)
|
|
|
|
// @COMPAT: Deprecated since 2.1.5
|
|
add_schema(schema_validator_rng, &zero, "pacemaker-next",
|
|
- NULL, NULL, FALSE, -1);
|
|
+ NULL, NULL, FALSE);
|
|
|
|
add_schema(schema_validator_none, &zero, PCMK__VALUE_NONE,
|
|
- NULL, NULL, FALSE, -1);
|
|
+ NULL, NULL, FALSE);
|
|
}
|
|
|
|
static gboolean
|
|
@@ -1290,17 +1273,12 @@ pcmk__log_known_schemas(void)
|
|
for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
struct schema_s *schema = iter->data;
|
|
|
|
- if (schema->after_transform < 0) {
|
|
- crm_debug("known_schemas[%d] => %s", lpc, schema->name);
|
|
-
|
|
- } else if (schema->transform != NULL) {
|
|
- crm_debug("known_schemas[%d] => %s (upgrades to %d with %s.xsl)",
|
|
- lpc, schema->name, schema->after_transform,
|
|
- schema->transform);
|
|
+ if (schema->transform != NULL) {
|
|
+ crm_debug("known_schemas[%d] => %s (upgrades with %s.xsl)",
|
|
+ lpc, schema->name, schema->transform);
|
|
|
|
} else {
|
|
- crm_debug("known_schemas[%d] => %s (upgrades to %d)",
|
|
- lpc, schema->name, schema->after_transform);
|
|
+ crm_debug("known_schemas[%d] => %s", lpc, schema->name);
|
|
}
|
|
|
|
lpc++;
|
|
--
|
|
2.31.1
|
|
|
|
From 645bb233e52b9f5f559ffcd354b2f4ef0bcdee90 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Mon, 6 Nov 2023 08:22:04 -0500
|
|
Subject: [PATCH 15/20] Refactor: libcrmcommon: Remove unnecessary schema code.
|
|
|
|
The block that sets the version if we didn't previously do so is no
|
|
longer necessary. This block only executes if the version parameter is
|
|
all zeros, which at the moment is only "pacemaker-next" and "none". We
|
|
could probably guarantee this will continue to be the case.
|
|
|
|
Additionally, I don't see that this would even do anything useful
|
|
anymore. Scanning the name for a version number is going to fail for
|
|
"pacemaker-next" and "none". So really, this block was just handling
|
|
the possibility that we passed in no version number but that the name
|
|
contained a number.
|
|
|
|
And with that done, there's only one more spot using schema_scanf so we
|
|
can just replace that with a call to sscanf.
|
|
---
|
|
lib/common/schemas.c | 14 +-------------
|
|
1 file changed, 1 insertion(+), 13 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index e33d3c7..7b91f71 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -32,9 +32,6 @@ typedef struct {
|
|
|
|
#define SCHEMA_ZERO { .v = { 0, 0 } }
|
|
|
|
-#define schema_scanf(s, prefix, version, suffix) \
|
|
- sscanf((s), prefix "%hhu.%hhu" suffix, &((version).v[0]), &((version).v[1]))
|
|
-
|
|
#define schema_strdup_printf(prefix, version, suffix) \
|
|
crm_strdup_printf(prefix "%u.%u" suffix, (version).v[0], (version).v[1])
|
|
|
|
@@ -139,9 +136,7 @@ xml_latest_schema(void)
|
|
static inline bool
|
|
version_from_filename(const char *filename, schema_version_t *version)
|
|
{
|
|
- int rc = schema_scanf(filename, "pacemaker-", *version, ".rng");
|
|
-
|
|
- return (rc == 2);
|
|
+ return sscanf(filename, "pacemaker-%hhu.%hhu.rng", &(version->v[0]), &(version->v[1])) == 2;
|
|
}
|
|
|
|
static int
|
|
@@ -203,7 +198,6 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
{
|
|
struct schema_s *schema = NULL;
|
|
int last = g_list_length(known_schemas);
|
|
- bool have_version = false;
|
|
|
|
schema = calloc(1, sizeof(struct schema_s));
|
|
CRM_ASSERT(schema != NULL);
|
|
@@ -214,14 +208,8 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
schema->transform_onleave = transform_onleave;
|
|
|
|
if (version->v[0] || version->v[1]) {
|
|
- have_version = true;
|
|
- }
|
|
-
|
|
- if (have_version) {
|
|
schema->name = schema_strdup_printf("pacemaker-", *version, "");
|
|
} else {
|
|
- CRM_ASSERT(name != NULL);
|
|
- schema_scanf(name, "%*[^-]-", schema->version, "");
|
|
schema->name = strdup(name);
|
|
CRM_ASSERT(schema->name != NULL);
|
|
}
|
|
--
|
|
2.31.1
|
|
|
|
From 0943f1ff0a9e72e88c5a234a32bb83d0f2e02c84 Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Fri, 17 Nov 2023 09:42:55 -0500
|
|
Subject: [PATCH 16/20] Refactor: libcrmcommon: Improve
|
|
xml_find_x_0_schema_index.
|
|
|
|
* Lots of comments to explain how it works.
|
|
|
|
* Walk the list backwards, stopping on the first one in the major
|
|
version series. This means the first one no longer has to be X.0.
|
|
|
|
* Require that known_schemas be non-NULL.
|
|
|
|
* Don't use the returned index to also mean we've found something since
|
|
that means if the index we actually want to return is 0, the function
|
|
will have to run every time.
|
|
---
|
|
lib/common/schemas.c | 62 +++++++++++++++++++++++++++++---------------
|
|
1 file changed, 41 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 7b91f71..466ad5a 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -85,45 +85,65 @@ xml_latest_schema_index(void)
|
|
static int
|
|
xml_find_x_0_schema_index(void)
|
|
{
|
|
+ /* We can't just use best to determine whether we've found the index
|
|
+ * or not. What if we have a very long list of schemas all in the
|
|
+ * same major version series? We'd return 0 for that, which means
|
|
+ * we would still run this function every time.
|
|
+ */
|
|
+ static bool found = false;
|
|
static int best = 0;
|
|
- int i = 0;
|
|
+ int i;
|
|
+ GList *best_node = NULL;
|
|
struct schema_s *best_schema = NULL;
|
|
|
|
- if (best != 0) {
|
|
+ if (found) {
|
|
return best;
|
|
}
|
|
|
|
+ CRM_ASSERT(known_schemas != NULL);
|
|
+
|
|
/* Get the most recent schema so we can look at its version number. */
|
|
best = xml_latest_schema_index();
|
|
- best_schema = g_list_nth(known_schemas, best)->data;
|
|
+ best_node = g_list_nth(known_schemas, best);
|
|
+ best_schema = best_node->data;
|
|
+
|
|
+ /* If this is a singleton list, we're done. */
|
|
+ if (pcmk__list_of_1(known_schemas)) {
|
|
+ goto done;
|
|
+ }
|
|
|
|
- /* Iterate over the schema list until we find a schema with the same major
|
|
- * version as best, and with a minor version number of 0.
|
|
- *
|
|
- * This assumes that the first schema in a major series is always X.0,
|
|
- * which seems like a safe assumption.
|
|
+ /* Start comparing the list from the node before the best schema (there's
|
|
+ * no point in comparing something to itself). Then, 'i' is an index
|
|
+ * starting at the best schema and will always point at the node after
|
|
+ * 'iter'. This makes it the value we want to return when we find what
|
|
+ * we're looking for.
|
|
*/
|
|
- for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
+ i = best;
|
|
+
|
|
+ for (GList *iter = best_node->prev; iter != NULL; iter = iter->prev) {
|
|
struct schema_s *schema = iter->data;
|
|
|
|
- /* If we hit the initial best schema, the only things left in the list
|
|
- * are "pacemaker-next" and "none" which aren't worth checking.
|
|
+ /* We've found a schema in an older major version series. Return
|
|
+ * the index of the first one in the same major version series as
|
|
+ * the best schema.
|
|
*/
|
|
- if (schema == best_schema) {
|
|
- break;
|
|
- }
|
|
-
|
|
- if (schema->version.v[0] == best_schema->version.v[0] &&
|
|
- schema->version.v[1] == 0) {
|
|
+ if (schema->version.v[0] < best_schema->version.v[0]) {
|
|
best = i;
|
|
- return best;
|
|
+ goto done;
|
|
+
|
|
+ /* We're out of list to examine. This probably means there was only
|
|
+ * one major version series, so return index 0.
|
|
+ */
|
|
+ } else if (iter->prev == NULL) {
|
|
+ best = 0;
|
|
+ goto done;
|
|
}
|
|
|
|
- i++;
|
|
+ i--;
|
|
}
|
|
|
|
- /* If we got here, we never found a match. Just return the latest. */
|
|
- best = xml_latest_schema_index();
|
|
+done:
|
|
+ found = true;
|
|
return best;
|
|
}
|
|
|
|
--
|
|
2.31.1
|
|
|
|
From eeeb36338f48d40f9f15a51c18aeca533b6c260d Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Fri, 17 Nov 2023 11:18:34 -0500
|
|
Subject: [PATCH 17/20] Refactor: libcrmcommon: Add a parameter to a couple
|
|
schema functions.
|
|
|
|
Instead of assuming known_schemas, pass the list to use as a parameter.
|
|
---
|
|
lib/common/schemas.c | 22 +++++++++++-----------
|
|
1 file changed, 11 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 466ad5a..9d98695 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -73,17 +73,17 @@ xml_log(int priority, const char *fmt, ...)
|
|
}
|
|
|
|
static int
|
|
-xml_latest_schema_index(void)
|
|
+xml_latest_schema_index(GList *schemas)
|
|
{
|
|
// @COMPAT: pacemaker-next is deprecated since 2.1.5
|
|
// FIXME: This function assumes at least three schemas have been added
|
|
// before it has been called for the first time.
|
|
- return g_list_length(known_schemas) - 3; // index from 0, ignore "pacemaker-next"/"none"
|
|
+ return g_list_length(schemas) - 3; // index from 0, ignore "pacemaker-next"/"none"
|
|
}
|
|
|
|
/* Return the index of the most recent X.0 schema. */
|
|
static int
|
|
-xml_find_x_0_schema_index(void)
|
|
+xml_find_x_0_schema_index(GList *schemas)
|
|
{
|
|
/* We can't just use best to determine whether we've found the index
|
|
* or not. What if we have a very long list of schemas all in the
|
|
@@ -100,15 +100,15 @@ xml_find_x_0_schema_index(void)
|
|
return best;
|
|
}
|
|
|
|
- CRM_ASSERT(known_schemas != NULL);
|
|
+ CRM_ASSERT(schemas != NULL);
|
|
|
|
/* Get the most recent schema so we can look at its version number. */
|
|
- best = xml_latest_schema_index();
|
|
- best_node = g_list_nth(known_schemas, best);
|
|
+ best = xml_latest_schema_index(schemas);
|
|
+ best_node = g_list_nth(schemas, best);
|
|
best_schema = best_node->data;
|
|
|
|
/* If this is a singleton list, we're done. */
|
|
- if (pcmk__list_of_1(known_schemas)) {
|
|
+ if (pcmk__list_of_1(schemas)) {
|
|
goto done;
|
|
}
|
|
|
|
@@ -150,7 +150,7 @@ done:
|
|
const char *
|
|
xml_latest_schema(void)
|
|
{
|
|
- return get_schema_name(xml_latest_schema_index());
|
|
+ return get_schema_name(xml_latest_schema_index(known_schemas));
|
|
}
|
|
|
|
static inline bool
|
|
@@ -1010,7 +1010,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
{
|
|
xmlNode *xml = NULL;
|
|
char *value = NULL;
|
|
- int max_stable_schemas = xml_latest_schema_index();
|
|
+ int max_stable_schemas = xml_latest_schema_index(known_schemas);
|
|
int lpc = 0, match = -1, rc = pcmk_ok;
|
|
int next = -1; /* -1 denotes "inactive" value */
|
|
xmlRelaxNGValidityErrorFunc error_handler =
|
|
@@ -1173,7 +1173,7 @@ cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
|
|
|
|
int version = get_schema_version(value);
|
|
int orig_version = version;
|
|
- int min_version = xml_find_x_0_schema_index();
|
|
+ int min_version = xml_find_x_0_schema_index(known_schemas);
|
|
|
|
if (version < min_version) {
|
|
// Current configuration schema is not acceptable, try to update
|
|
@@ -1235,7 +1235,7 @@ cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
|
|
free_xml(*xml);
|
|
*xml = converted;
|
|
|
|
- if (version < xml_latest_schema_index()) {
|
|
+ if (version < xml_latest_schema_index(known_schemas)) {
|
|
if (to_logs) {
|
|
pcmk__config_warn("Configuration with schema %s was "
|
|
"internally upgraded to acceptable (but "
|
|
--
|
|
2.31.1
|
|
|
|
From 12e7b982da61c6cc6cf01164d45bb8f7b0255a8a Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Fri, 17 Nov 2023 11:30:18 -0500
|
|
Subject: [PATCH 18/20] Refactor: libcrmcommon: Rename several schema-related
|
|
types.
|
|
|
|
Give them pcmk__ names indicating they are private. This is in
|
|
preparation for moving them out into a header file.
|
|
---
|
|
lib/common/schemas.c | 80 ++++++++++++++++++++++----------------------
|
|
1 file changed, 40 insertions(+), 40 deletions(-)
|
|
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 9d98695..cf8f325 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -28,7 +28,7 @@
|
|
|
|
typedef struct {
|
|
unsigned char v[2];
|
|
-} schema_version_t;
|
|
+} pcmk__schema_version_t;
|
|
|
|
#define SCHEMA_ZERO { .v = { 0, 0 } }
|
|
|
|
@@ -41,20 +41,20 @@ typedef struct {
|
|
xmlRelaxNGParserCtxtPtr parser;
|
|
} relaxng_ctx_cache_t;
|
|
|
|
-enum schema_validator_e {
|
|
- schema_validator_none,
|
|
- schema_validator_rng
|
|
+enum pcmk__schema_validator {
|
|
+ pcmk__schema_validator_none,
|
|
+ pcmk__schema_validator_rng
|
|
};
|
|
|
|
-struct schema_s {
|
|
+typedef struct {
|
|
char *name;
|
|
char *transform;
|
|
void *cache;
|
|
- enum schema_validator_e validator;
|
|
- schema_version_t version;
|
|
+ enum pcmk__schema_validator validator;
|
|
+ pcmk__schema_version_t version;
|
|
char *transform_enter;
|
|
bool transform_onleave;
|
|
-};
|
|
+} pcmk__schema_t;
|
|
|
|
static GList *known_schemas = NULL;
|
|
static bool silent_logging = FALSE;
|
|
@@ -94,7 +94,7 @@ xml_find_x_0_schema_index(GList *schemas)
|
|
static int best = 0;
|
|
int i;
|
|
GList *best_node = NULL;
|
|
- struct schema_s *best_schema = NULL;
|
|
+ pcmk__schema_t *best_schema = NULL;
|
|
|
|
if (found) {
|
|
return best;
|
|
@@ -121,7 +121,7 @@ xml_find_x_0_schema_index(GList *schemas)
|
|
i = best;
|
|
|
|
for (GList *iter = best_node->prev; iter != NULL; iter = iter->prev) {
|
|
- struct schema_s *schema = iter->data;
|
|
+ pcmk__schema_t *schema = iter->data;
|
|
|
|
/* We've found a schema in an older major version series. Return
|
|
* the index of the first one in the same major version series as
|
|
@@ -154,7 +154,7 @@ xml_latest_schema(void)
|
|
}
|
|
|
|
static inline bool
|
|
-version_from_filename(const char *filename, schema_version_t *version)
|
|
+version_from_filename(const char *filename, pcmk__schema_version_t *version)
|
|
{
|
|
return sscanf(filename, "pacemaker-%hhu.%hhu.rng", &(version->v[0]), &(version->v[1])) == 2;
|
|
}
|
|
@@ -163,7 +163,7 @@ static int
|
|
schema_filter(const struct dirent *a)
|
|
{
|
|
int rc = 0;
|
|
- schema_version_t version = SCHEMA_ZERO;
|
|
+ pcmk__schema_version_t version = SCHEMA_ZERO;
|
|
|
|
if (strstr(a->d_name, "pacemaker-") != a->d_name) {
|
|
/* crm_trace("%s - wrong prefix", a->d_name); */
|
|
@@ -185,8 +185,8 @@ schema_filter(const struct dirent *a)
|
|
static int
|
|
schema_sort(const struct dirent **a, const struct dirent **b)
|
|
{
|
|
- schema_version_t a_version = SCHEMA_ZERO;
|
|
- schema_version_t b_version = SCHEMA_ZERO;
|
|
+ pcmk__schema_version_t a_version = SCHEMA_ZERO;
|
|
+ pcmk__schema_version_t b_version = SCHEMA_ZERO;
|
|
|
|
if (!version_from_filename(a[0]->d_name, &a_version)
|
|
|| !version_from_filename(b[0]->d_name, &b_version)) {
|
|
@@ -212,14 +212,14 @@ schema_sort(const struct dirent **a, const struct dirent **b)
|
|
* through \c add_schema_by_version.
|
|
*/
|
|
static void
|
|
-add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
+add_schema(enum pcmk__schema_validator validator, const pcmk__schema_version_t *version,
|
|
const char *name, const char *transform,
|
|
const char *transform_enter, bool transform_onleave)
|
|
{
|
|
- struct schema_s *schema = NULL;
|
|
+ pcmk__schema_t *schema = NULL;
|
|
int last = g_list_length(known_schemas);
|
|
|
|
- schema = calloc(1, sizeof(struct schema_s));
|
|
+ schema = calloc(1, sizeof(pcmk__schema_t));
|
|
CRM_ASSERT(schema != NULL);
|
|
|
|
schema->validator = validator;
|
|
@@ -284,7 +284,7 @@ add_schema(enum schema_validator_e validator, const schema_version_t *version,
|
|
* . name convention: (see "upgrade-enter")
|
|
*/
|
|
static int
|
|
-add_schema_by_version(const schema_version_t *version, bool transform_expected)
|
|
+add_schema_by_version(const pcmk__schema_version_t *version, bool transform_expected)
|
|
{
|
|
bool transform_onleave = FALSE;
|
|
int rc = pcmk_rc_ok;
|
|
@@ -343,7 +343,7 @@ add_schema_by_version(const schema_version_t *version, bool transform_expected)
|
|
rc = ENOENT;
|
|
}
|
|
|
|
- add_schema(schema_validator_rng, version, NULL,
|
|
+ add_schema(pcmk__schema_validator_rng, version, NULL,
|
|
transform_upgrade, transform_enter, transform_onleave);
|
|
|
|
free(transform_upgrade);
|
|
@@ -397,7 +397,7 @@ crm_schema_init(void)
|
|
int lpc, max;
|
|
char *base = pcmk__xml_artefact_root(pcmk__xml_artefact_ns_legacy_rng);
|
|
struct dirent **namelist = NULL;
|
|
- const schema_version_t zero = SCHEMA_ZERO;
|
|
+ const pcmk__schema_version_t zero = SCHEMA_ZERO;
|
|
|
|
wrap_libxslt(false);
|
|
|
|
@@ -410,7 +410,7 @@ crm_schema_init(void)
|
|
free(base);
|
|
for (lpc = 0; lpc < max; lpc++) {
|
|
bool transform_expected = FALSE;
|
|
- schema_version_t version = SCHEMA_ZERO;
|
|
+ pcmk__schema_version_t version = SCHEMA_ZERO;
|
|
|
|
if (!version_from_filename(namelist[lpc]->d_name, &version)) {
|
|
// Shouldn't be possible, but makes static analysis happy
|
|
@@ -419,7 +419,7 @@ crm_schema_init(void)
|
|
continue;
|
|
}
|
|
if ((lpc + 1) < max) {
|
|
- schema_version_t next_version = SCHEMA_ZERO;
|
|
+ pcmk__schema_version_t next_version = SCHEMA_ZERO;
|
|
|
|
if (version_from_filename(namelist[lpc+1]->d_name, &next_version)
|
|
&& (version.v[0] < next_version.v[0])) {
|
|
@@ -440,10 +440,10 @@ crm_schema_init(void)
|
|
}
|
|
|
|
// @COMPAT: Deprecated since 2.1.5
|
|
- add_schema(schema_validator_rng, &zero, "pacemaker-next",
|
|
+ add_schema(pcmk__schema_validator_rng, &zero, "pacemaker-next",
|
|
NULL, NULL, FALSE);
|
|
|
|
- add_schema(schema_validator_none, &zero, PCMK__VALUE_NONE,
|
|
+ add_schema(pcmk__schema_validator_none, &zero, PCMK__VALUE_NONE,
|
|
NULL, NULL, FALSE);
|
|
}
|
|
|
|
@@ -533,14 +533,14 @@ validate_with_relaxng(xmlDocPtr doc, xmlRelaxNGValidityErrorFunc error_handler,
|
|
static void
|
|
free_schema(gpointer data)
|
|
{
|
|
- struct schema_s *schema = data;
|
|
+ pcmk__schema_t *schema = data;
|
|
relaxng_ctx_cache_t *ctx = NULL;
|
|
|
|
switch (schema->validator) {
|
|
- case schema_validator_none: // not cached
|
|
+ case pcmk__schema_validator_none: // not cached
|
|
break;
|
|
|
|
- case schema_validator_rng: // cached
|
|
+ case pcmk__schema_validator_rng: // cached
|
|
ctx = (relaxng_ctx_cache_t *) schema->cache;
|
|
if (ctx == NULL) {
|
|
break;
|
|
@@ -582,7 +582,7 @@ crm_schema_cleanup(void)
|
|
}
|
|
|
|
static gboolean
|
|
-validate_with(xmlNode *xml, struct schema_s *schema, xmlRelaxNGValidityErrorFunc error_handler, void* error_handler_context)
|
|
+validate_with(xmlNode *xml, pcmk__schema_t *schema, xmlRelaxNGValidityErrorFunc error_handler, void* error_handler_context)
|
|
{
|
|
gboolean valid = FALSE;
|
|
char *file = NULL;
|
|
@@ -592,7 +592,7 @@ validate_with(xmlNode *xml, struct schema_s *schema, xmlRelaxNGValidityErrorFunc
|
|
return FALSE;
|
|
}
|
|
|
|
- if (schema->validator == schema_validator_none) {
|
|
+ if (schema->validator == pcmk__schema_validator_none) {
|
|
return TRUE;
|
|
}
|
|
|
|
@@ -607,7 +607,7 @@ validate_with(xmlNode *xml, struct schema_s *schema, xmlRelaxNGValidityErrorFunc
|
|
crm_trace("Validating with %s (type=%d)",
|
|
pcmk__s(file, "missing schema"), schema->validator);
|
|
switch (schema->validator) {
|
|
- case schema_validator_rng:
|
|
+ case pcmk__schema_validator_rng:
|
|
cache = (relaxng_ctx_cache_t **) &(schema->cache);
|
|
valid = validate_with_relaxng(xml->doc, error_handler, error_handler_context, file, cache);
|
|
break;
|
|
@@ -621,7 +621,7 @@ validate_with(xmlNode *xml, struct schema_s *schema, xmlRelaxNGValidityErrorFunc
|
|
}
|
|
|
|
static bool
|
|
-validate_with_silent(xmlNode *xml, struct schema_s *schema)
|
|
+validate_with_silent(xmlNode *xml, pcmk__schema_t *schema)
|
|
{
|
|
bool rc, sl_backup = silent_logging;
|
|
silent_logging = TRUE;
|
|
@@ -710,7 +710,7 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
bool valid = FALSE;
|
|
|
|
for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
- struct schema_s *schema = iter->data;
|
|
+ pcmk__schema_t *schema = iter->data;
|
|
|
|
if (validate_with(xml_blob, schema, NULL, NULL)) {
|
|
valid = TRUE;
|
|
@@ -726,7 +726,7 @@ pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidity
|
|
if (strcmp(validation, PCMK__VALUE_NONE) == 0) {
|
|
return TRUE;
|
|
} else if (version < g_list_length(known_schemas)) {
|
|
- struct schema_s *schema = g_list_nth_data(known_schemas, version);
|
|
+ pcmk__schema_t *schema = g_list_nth_data(known_schemas, version);
|
|
return validate_with(xml_blob, schema, error_handler,
|
|
error_handler_context);
|
|
}
|
|
@@ -918,7 +918,7 @@ apply_transformation(xmlNode *xml, const char *transform, gboolean to_logs)
|
|
* \note Only emits warnings about enter/leave phases in case of issues.
|
|
*/
|
|
static xmlNode *
|
|
-apply_upgrade(xmlNode *xml, const struct schema_s *schema, gboolean to_logs)
|
|
+apply_upgrade(xmlNode *xml, const pcmk__schema_t *schema, gboolean to_logs)
|
|
{
|
|
bool transform_onleave = schema->transform_onleave;
|
|
char *transform_leave;
|
|
@@ -972,7 +972,7 @@ apply_upgrade(xmlNode *xml, const struct schema_s *schema, gboolean to_logs)
|
|
const char *
|
|
get_schema_name(int version)
|
|
{
|
|
- struct schema_s *schema = g_list_nth_data(known_schemas, version);
|
|
+ pcmk__schema_t *schema = g_list_nth_data(known_schemas, version);
|
|
|
|
if (schema == NULL) {
|
|
return "unknown";
|
|
@@ -991,7 +991,7 @@ get_schema_version(const char *name)
|
|
}
|
|
|
|
for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
- struct schema_s *schema = iter->data;
|
|
+ pcmk__schema_t *schema = iter->data;
|
|
|
|
if (pcmk__str_eq(name, schema->name, pcmk__str_casei)) {
|
|
return lpc;
|
|
@@ -1052,7 +1052,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
* easier than trying to get all the loop indices we're using here
|
|
* sorted out and working correctly.
|
|
*/
|
|
- struct schema_s *schema = g_list_nth_data(known_schemas, lpc);
|
|
+ pcmk__schema_t *schema = g_list_nth_data(known_schemas, lpc);
|
|
|
|
crm_debug("Testing '%s' validation (%d of %d)",
|
|
pcmk__s(schema->name, "<unset>"), lpc, max_stable_schemas);
|
|
@@ -1085,7 +1085,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
|
|
if (rc == pcmk_ok && transform) {
|
|
xmlNode *upgrade = NULL;
|
|
- struct schema_s *next_schema = NULL;
|
|
+ pcmk__schema_t *next_schema = NULL;
|
|
next = lpc+1;
|
|
|
|
if (next > max_stable_schemas) {
|
|
@@ -1151,7 +1151,7 @@ update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform,
|
|
}
|
|
|
|
if (*best > match && *best) {
|
|
- struct schema_s *best_schema = g_list_nth_data(known_schemas, *best);
|
|
+ pcmk__schema_t *best_schema = g_list_nth_data(known_schemas, *best);
|
|
|
|
crm_info("%s the configuration from %s to %s",
|
|
transform?"Transformed":"Upgraded", pcmk__s(value, "<none>"),
|
|
@@ -1279,7 +1279,7 @@ pcmk__log_known_schemas(void)
|
|
int lpc = 0;
|
|
|
|
for (GList *iter = known_schemas; iter != NULL; iter = iter->next) {
|
|
- struct schema_s *schema = iter->data;
|
|
+ pcmk__schema_t *schema = iter->data;
|
|
|
|
if (schema->transform != NULL) {
|
|
crm_debug("known_schemas[%d] => %s (upgrades with %s.xsl)",
|
|
--
|
|
2.31.1
|
|
|
|
From 97b3fa3462039d4d7bdad6c6ff328a5124977e5f Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Fri, 17 Nov 2023 11:32:55 -0500
|
|
Subject: [PATCH 19/20] Refactor: libcrmcommon: Make various schema stuff
|
|
non-static.
|
|
|
|
This is the minimum amount necessary to make the function unit testable.
|
|
None of this is intended to ever become public.
|
|
---
|
|
lib/common/crmcommon_private.h | 26 ++++++++++++++++++++++++++
|
|
lib/common/schemas.c | 25 ++++---------------------
|
|
2 files changed, 30 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h
|
|
index 121d663..6ab9de1 100644
|
|
--- a/lib/common/crmcommon_private.h
|
|
+++ b/lib/common/crmcommon_private.h
|
|
@@ -283,4 +283,30 @@ void pcmk__register_patchset_messages(pcmk__output_t *out);
|
|
#define PCMK__PW_BUFFER_LEN 500
|
|
|
|
|
|
+/*
|
|
+ * Schemas
|
|
+ */
|
|
+typedef struct {
|
|
+ unsigned char v[2];
|
|
+} pcmk__schema_version_t;
|
|
+
|
|
+enum pcmk__schema_validator {
|
|
+ pcmk__schema_validator_none,
|
|
+ pcmk__schema_validator_rng
|
|
+};
|
|
+
|
|
+typedef struct {
|
|
+ char *name;
|
|
+ char *transform;
|
|
+ void *cache;
|
|
+ enum pcmk__schema_validator validator;
|
|
+ pcmk__schema_version_t version;
|
|
+ char *transform_enter;
|
|
+ bool transform_onleave;
|
|
+} pcmk__schema_t;
|
|
+
|
|
+G_GNUC_INTERNAL
|
|
+int pcmk__find_x_0_schema_index(GList *schemas);
|
|
+
|
|
+
|
|
#endif // CRMCOMMON_PRIVATE__H
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index cf8f325..83334b4 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -26,9 +26,7 @@
|
|
#include <crm/common/xml.h>
|
|
#include <crm/common/xml_internal.h> /* PCMK__XML_LOG_BASE */
|
|
|
|
-typedef struct {
|
|
- unsigned char v[2];
|
|
-} pcmk__schema_version_t;
|
|
+#include "crmcommon_private.h"
|
|
|
|
#define SCHEMA_ZERO { .v = { 0, 0 } }
|
|
|
|
@@ -41,21 +39,6 @@ typedef struct {
|
|
xmlRelaxNGParserCtxtPtr parser;
|
|
} relaxng_ctx_cache_t;
|
|
|
|
-enum pcmk__schema_validator {
|
|
- pcmk__schema_validator_none,
|
|
- pcmk__schema_validator_rng
|
|
-};
|
|
-
|
|
-typedef struct {
|
|
- char *name;
|
|
- char *transform;
|
|
- void *cache;
|
|
- enum pcmk__schema_validator validator;
|
|
- pcmk__schema_version_t version;
|
|
- char *transform_enter;
|
|
- bool transform_onleave;
|
|
-} pcmk__schema_t;
|
|
-
|
|
static GList *known_schemas = NULL;
|
|
static bool silent_logging = FALSE;
|
|
|
|
@@ -82,8 +65,8 @@ xml_latest_schema_index(GList *schemas)
|
|
}
|
|
|
|
/* Return the index of the most recent X.0 schema. */
|
|
-static int
|
|
-xml_find_x_0_schema_index(GList *schemas)
|
|
+int
|
|
+pcmk__find_x_0_schema_index(GList *schemas)
|
|
{
|
|
/* We can't just use best to determine whether we've found the index
|
|
* or not. What if we have a very long list of schemas all in the
|
|
@@ -1173,7 +1156,7 @@ cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
|
|
|
|
int version = get_schema_version(value);
|
|
int orig_version = version;
|
|
- int min_version = xml_find_x_0_schema_index(known_schemas);
|
|
+ int min_version = pcmk__find_x_0_schema_index(known_schemas);
|
|
|
|
if (version < min_version) {
|
|
// Current configuration schema is not acceptable, try to update
|
|
--
|
|
2.31.1
|
|
|
|
From c4c093c0785e06ca3371556b19ede1d5b44d090a Mon Sep 17 00:00:00 2001
|
|
From: Chris Lumens <clumens@redhat.com>
|
|
Date: Fri, 17 Nov 2023 12:39:53 -0500
|
|
Subject: [PATCH 20/20] Test: libcrmcommon: Add unit tests for
|
|
pcmk__xml_find_x_0_schema_index.
|
|
|
|
This requires making various things in the function conditional, which I
|
|
kind of hate. But, it all comes down to the fact that when we are
|
|
running for real, we're adding the pacemaker-next/none schemas with
|
|
crm_schema_init.
|
|
|
|
When we are unit testing, we aren't doing any of that. The only
|
|
"schemas" we have are the ones we are adding directly. So, the list has
|
|
two items fewer than the real function expects. I think this is okay
|
|
and doesn't totally invalidating the testing.
|
|
---
|
|
configure.ac | 1 +
|
|
lib/common/schemas.c | 33 +++++-
|
|
lib/common/tests/Makefile.am | 1 +
|
|
lib/common/tests/schemas/Makefile.am | 16 +++
|
|
.../pcmk__xml_find_x_0_schema_index_test.c | 112 ++++++++++++++++++
|
|
5 files changed, 161 insertions(+), 2 deletions(-)
|
|
create mode 100644 lib/common/tests/schemas/Makefile.am
|
|
create mode 100644 lib/common/tests/schemas/pcmk__xml_find_x_0_schema_index_test.c
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 6bff02e..9eb7539 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -2153,6 +2153,7 @@ AC_CONFIG_FILES(Makefile \
|
|
lib/common/tests/output/Makefile \
|
|
lib/common/tests/procfs/Makefile \
|
|
lib/common/tests/results/Makefile \
|
|
+ lib/common/tests/schemas/Makefile \
|
|
lib/common/tests/scores/Makefile \
|
|
lib/common/tests/strings/Makefile \
|
|
lib/common/tests/utils/Makefile \
|
|
diff --git a/lib/common/schemas.c b/lib/common/schemas.c
|
|
index 83334b4..372e872 100644
|
|
--- a/lib/common/schemas.c
|
|
+++ b/lib/common/schemas.c
|
|
@@ -60,8 +60,13 @@ xml_latest_schema_index(GList *schemas)
|
|
{
|
|
// @COMPAT: pacemaker-next is deprecated since 2.1.5
|
|
// FIXME: This function assumes at least three schemas have been added
|
|
- // before it has been called for the first time.
|
|
+ // before it has been called for the first time, which is only the case
|
|
+ // if we are not unit testing.
|
|
+#if defined(PCMK__UNIT_TESTING)
|
|
+ return g_list_length(schemas) - 1; // index from 0
|
|
+#else
|
|
return g_list_length(schemas) - 3; // index from 0, ignore "pacemaker-next"/"none"
|
|
+#endif
|
|
}
|
|
|
|
/* Return the index of the most recent X.0 schema. */
|
|
@@ -73,8 +78,17 @@ pcmk__find_x_0_schema_index(GList *schemas)
|
|
* same major version series? We'd return 0 for that, which means
|
|
* we would still run this function every time.
|
|
*/
|
|
+#if defined(PCMK__UNIT_TESTING)
|
|
+ /* If we're unit testing, these can't be static because they'll stick
|
|
+ * around from one test run to the next. They need to be cleared out
|
|
+ * every time.
|
|
+ */
|
|
+ bool found = false;
|
|
+ int best = 0;
|
|
+#else
|
|
static bool found = false;
|
|
static int best = 0;
|
|
+#endif
|
|
int i;
|
|
GList *best_node = NULL;
|
|
pcmk__schema_t *best_schema = NULL;
|
|
@@ -90,10 +104,25 @@ pcmk__find_x_0_schema_index(GList *schemas)
|
|
best_node = g_list_nth(schemas, best);
|
|
best_schema = best_node->data;
|
|
|
|
- /* If this is a singleton list, we're done. */
|
|
+ /* If we are unit testing, we don't add the pacemaker-next/none schemas
|
|
+ * to the list because we're not using the standard schema adding
|
|
+ * functions. Thus, a singleton list means we're done.
|
|
+ *
|
|
+ * On the other hand, if we are running as usually, we have those two
|
|
+ * schemas added to the list. A list of length three actually only has
|
|
+ * one useful schema. So we're still done.
|
|
+ *
|
|
+ * @COMPAT Change this when we stop adding those schemas.
|
|
+ */
|
|
+#if defined(PCMK__UNIT_TESTING)
|
|
if (pcmk__list_of_1(schemas)) {
|
|
goto done;
|
|
}
|
|
+#else
|
|
+ if (g_list_length(schemas) == 3) {
|
|
+ goto done;
|
|
+ }
|
|
+#endif
|
|
|
|
/* Start comparing the list from the node before the best schema (there's
|
|
* no point in comparing something to itself). Then, 'i' is an index
|
|
diff --git a/lib/common/tests/Makefile.am b/lib/common/tests/Makefile.am
|
|
index c0407e5..22fb32e 100644
|
|
--- a/lib/common/tests/Makefile.am
|
|
+++ b/lib/common/tests/Makefile.am
|
|
@@ -21,6 +21,7 @@ SUBDIRS = \
|
|
options \
|
|
output \
|
|
results \
|
|
+ schemas \
|
|
scores \
|
|
strings \
|
|
utils \
|
|
diff --git a/lib/common/tests/schemas/Makefile.am b/lib/common/tests/schemas/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..5f485b3
|
|
--- /dev/null
|
|
+++ b/lib/common/tests/schemas/Makefile.am
|
|
@@ -0,0 +1,16 @@
|
|
+#
|
|
+# Copyright 2023 the Pacemaker project contributors
|
|
+#
|
|
+# The version control history for this file may have further details.
|
|
+#
|
|
+# This source code is licensed under the GNU General Public License version 2
|
|
+# or later (GPLv2+) WITHOUT ANY WARRANTY.
|
|
+#
|
|
+
|
|
+include $(top_srcdir)/mk/tap.mk
|
|
+include $(top_srcdir)/mk/unittest.mk
|
|
+
|
|
+# Add "_test" to the end of all test program names to simplify .gitignore.
|
|
+check_PROGRAMS = pcmk__xml_find_x_0_schema_index_test
|
|
+
|
|
+TESTS = $(check_PROGRAMS)
|
|
diff --git a/lib/common/tests/schemas/pcmk__xml_find_x_0_schema_index_test.c b/lib/common/tests/schemas/pcmk__xml_find_x_0_schema_index_test.c
|
|
new file mode 100644
|
|
index 0000000..9f16ba1
|
|
--- /dev/null
|
|
+++ b/lib/common/tests/schemas/pcmk__xml_find_x_0_schema_index_test.c
|
|
@@ -0,0 +1,112 @@
|
|
+/*
|
|
+ * Copyright 2023 the Pacemaker project contributors
|
|
+ *
|
|
+ * The version control history for this file may have further details.
|
|
+ *
|
|
+ * This source code is licensed under the GNU General Public License version 2
|
|
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
|
|
+ */
|
|
+
|
|
+#include <crm_internal.h>
|
|
+#include <crm/common/unittest_internal.h>
|
|
+
|
|
+#include <glib.h>
|
|
+
|
|
+#include "crmcommon_private.h"
|
|
+
|
|
+static pcmk__schema_t *
|
|
+mk_schema(const char *name, unsigned char x, unsigned char y)
|
|
+{
|
|
+ pcmk__schema_t *schema = malloc(sizeof(pcmk__schema_t));
|
|
+
|
|
+ schema->name = strdup(name);
|
|
+ schema->version.v[0] = x;
|
|
+ schema->version.v[1] = y;
|
|
+ return schema;
|
|
+}
|
|
+
|
|
+static void
|
|
+free_schema(void *data)
|
|
+{
|
|
+ pcmk__schema_t *schema = data;
|
|
+ free(schema->name);
|
|
+ free(schema);
|
|
+}
|
|
+
|
|
+static void
|
|
+empty_schema_list(void **state)
|
|
+{
|
|
+ pcmk__assert_asserts(pcmk__find_x_0_schema_index(NULL));
|
|
+}
|
|
+
|
|
+static void
|
|
+singleton_schema_list(void **state)
|
|
+{
|
|
+ GList *schemas = NULL;
|
|
+
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.0", 1, 0));
|
|
+ assert_int_equal(0, pcmk__find_x_0_schema_index(schemas));
|
|
+ g_list_free_full(schemas, free_schema);
|
|
+}
|
|
+
|
|
+static void
|
|
+one_major_version(void **state)
|
|
+{
|
|
+ GList *schemas = NULL;
|
|
+
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.0", 1, 0));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.2", 1, 2));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.3", 1, 3));
|
|
+ assert_int_equal(0, pcmk__find_x_0_schema_index(schemas));
|
|
+ g_list_free_full(schemas, free_schema);
|
|
+}
|
|
+
|
|
+static void
|
|
+first_version_is_not_0(void **state)
|
|
+{
|
|
+ GList *schemas = NULL;
|
|
+
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.1", 1, 1));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.2", 1, 2));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.3", 1, 3));
|
|
+ assert_int_equal(0, pcmk__find_x_0_schema_index(schemas));
|
|
+ g_list_free_full(schemas, free_schema);
|
|
+}
|
|
+
|
|
+static void
|
|
+multiple_major_versions(void **state)
|
|
+{
|
|
+ GList *schemas = NULL;
|
|
+
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.0", 1, 0));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.1", 1, 1));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-2.0", 2, 0));
|
|
+ assert_int_equal(2, pcmk__find_x_0_schema_index(schemas));
|
|
+ g_list_free_full(schemas, free_schema);
|
|
+}
|
|
+
|
|
+static void
|
|
+many_versions(void **state)
|
|
+{
|
|
+ GList *schemas = NULL;
|
|
+
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.0", 1, 0));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.1", 1, 1));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-1.2", 1, 2));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-2.0", 2, 0));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-2.1", 2, 1));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-2.2", 2, 2));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-3.0", 3, 0));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-3.1", 3, 1));
|
|
+ schemas = g_list_append(schemas, mk_schema("pacemaker-3.2", 3, 2));
|
|
+ assert_int_equal(6, pcmk__find_x_0_schema_index(schemas));
|
|
+ g_list_free_full(schemas, free_schema);
|
|
+}
|
|
+
|
|
+PCMK__UNIT_TEST(NULL, NULL,
|
|
+ cmocka_unit_test(empty_schema_list),
|
|
+ cmocka_unit_test(singleton_schema_list),
|
|
+ cmocka_unit_test(one_major_version),
|
|
+ cmocka_unit_test(first_version_is_not_0),
|
|
+ cmocka_unit_test(multiple_major_versions),
|
|
+ cmocka_unit_test(many_versions))
|
|
--
|
|
2.31.1
|
|
|