diff --git a/.travis.yml b/.travis.yml index 1a1621c2c5..27b6cd3907 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,73 +1,73 @@ # Control file for the Travis autobuilder # https://docs.travis-ci.com/user/customizing-the-build/ language: c compiler: - gcc - clang # - cov-build env: global: # -- BEGIN Coverity Scan ENV # Used by https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh # The build command with all of the arguments that you would apply to a manual `cov-build` - COVERITY_SCAN_BUILD_COMMAND="make" # Email address for notifications related to this build - OWNER_EMAIL="andrew@beekhof.net" # Regular expression selects on which branches to run analysis # Be aware of quotas. Do not run on every branch/commit - COVERITY_SCAN_BRANCH_PATTERN="1.1" # COVERITY_SCAN_TOKEN via "travis encrypt" using the repo's public key - secure: "qnrF7L8RejLUY7URdNe7XP4Hu4R55C0tvAuMRg4EjVtelOpw+nIgA7BLiX19q/70VjFuKcGnMhW28TdYl0uwMMdWKKxmwTim04Sy3UfOE2BPeuQOBphr+8s9gd0U1MO8j2dZ84A40t5Mkk946wWZwT0okpjOr/PfBOZkU3o87FM=" # -- END Coverity Scan ENV # sudo add-apt-repository ppa:hotot-team before_install: - sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ trusty main" - sudo apt-get update -qq install: - - sudo apt-get install -qq automake autoconf chrpath libglib2.0-dev perl net-tools python libtool libxml2-dev bison flex uuid-dev libbz2-dev zlib1g-dev libltdl3-dev libgnutls-dev python-central python-dev libpam0g-dev libncurses5-dev libcorosync-dev libxslt1-dev libdbus-1-dev + - sudo apt-get install -qq automake autoconf chrpath libglib2.0-dev perl net-tools python libtool libxml2-dev bison flex uuid-dev libbz2-dev zlib1g-dev libltdl3-dev libgnutls-dev python-dev libpam0g-dev libncurses5-dev libcorosync-dev libxslt1-dev libdbus-1-dev - sudo apt-get install -qq cluster-glue-dev heartbeat-dev libheartbeat2-dev - sudo apt-get install -qq libqb-dev before_script: # Save and restore CC so that ./configure can pass - export CC_SAVED=$CC - export CC=`echo ${CC} | sed s/cov-build/gcc/` - ./autogen.sh - ./configure - export CC=$CC_SAVED script: - if test ${CC} != cov-build; then sudo make install-exec-local || true; fi - if test ${CC} != cov-build; then make && ./BasicSanity.sh -V; fi - if test ${CC} = cov-build; then export CC=gcc; bash ./travisci_build_coverity_scan.sh; fi #after_script: #after_success: after_failure: - lsb_release -a - sudo cat /etc/apt/sources.list - whoami - env | sort - cat include/config.h notifications: irc: "irc.freenode.org#pcmk" # email: # recipients: # - developers@clusterlabs.org # whitelist branches: only: - master - "1.1" diff --git a/include/crm/common/alerts_internal.h b/include/crm/common/alerts_internal.h index 92849d560a..8c325b8a8b 100644 --- a/include/crm/common/alerts_internal.h +++ b/include/crm/common/alerts_internal.h @@ -1,114 +1,112 @@ /* * Copyright (C) 2015 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ALERT_INTERNAL_H #define ALERT_INTERNAL_H #include #include /* Default-Timeout to use before killing a alerts script (in milliseconds) */ # define CRM_ALERT_DEFAULT_TIMEOUT_MS (30000) /* Default-Format-String used to pass timestamps to the alerts scripts */ # define CRM_ALERT_DEFAULT_TSTAMP_FORMAT "%H:%M:%S.%06N" typedef struct { char *name; char *value; } crm_alert_envvar_t; enum crm_alert_flags { crm_alert_none = 0x0000, crm_alert_node = 0x0001, crm_alert_fencing = 0x0002, crm_alert_resource = 0x0004, crm_alert_attribute = 0x0008, crm_alert_default = crm_alert_node|crm_alert_fencing|crm_alert_resource }; typedef struct { char *id; char *path; char *tstamp_format; char *recipient; char **select_attribute_name; GHashTable *envvars; int timeout; uint32_t flags; } crm_alert_entry_t; enum crm_alert_keys_e { CRM_alert_recipient = 0, CRM_alert_node, CRM_alert_nodeid, CRM_alert_rsc, CRM_alert_task, CRM_alert_interval, CRM_alert_desc, CRM_alert_status, CRM_alert_target_rc, CRM_alert_rc, CRM_alert_kind, CRM_alert_version, CRM_alert_node_sequence, CRM_alert_timestamp, CRM_alert_attribute_name, CRM_alert_attribute_value, CRM_alert_select_kind, CRM_alert_select_attribute_name }; #define CRM_ALERT_INTERNAL_KEY_MAX 16 #define CRM_ALERT_NODE_SEQUENCE "CRM_alert_node_sequence" extern const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3]; crm_alert_entry_t *crm_dup_alert_entry(crm_alert_entry_t *entry); crm_alert_envvar_t *crm_dup_alert_envvar(crm_alert_envvar_t *src); crm_alert_entry_t *crm_alert_entry_new(const char *id, const char *path); void crm_free_alert_entry(crm_alert_entry_t *entry); void crm_free_alert_envvar(crm_alert_envvar_t *entry); -void crm_set_alert_key(enum crm_alert_keys_e name, const char *value); -void crm_set_alert_key_int(enum crm_alert_keys_e name, int value); void crm_insert_alert_key(GHashTable *table, enum crm_alert_keys_e name, const char *value); void crm_insert_alert_key_int(GHashTable *table, enum crm_alert_keys_e name, int value); void crm_unset_alert_keys(void); void crm_set_envvar_list(crm_alert_entry_t *entry); void crm_unset_envvar_list(crm_alert_entry_t *entry); bool crm_patchset_contains_alert(xmlNode *msg, bool config); static inline const char * crm_alert_flag2text(enum crm_alert_flags flag) { switch (flag) { case crm_alert_node: return "node"; case crm_alert_fencing: return "fencing"; case crm_alert_resource: return "resource"; case crm_alert_attribute: return "attribute"; default: return "unknown"; } } #endif diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am index 56aa4c54c8..d8b593943a 100644 --- a/lib/common/Makefile.am +++ b/lib/common/Makefile.am @@ -1,49 +1,49 @@ # # Copyright (C) 2004 Andrew Beekhof # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # include $(top_srcdir)/Makefile.common AM_CPPFLAGS += -I$(top_builddir)/lib/gnu -I$(top_srcdir)/lib/gnu ## libraries lib_LTLIBRARIES = libcrmcommon.la # Can't use -Wcast-qual here because glib insists on pretending things are const # when they're not and thus we need the crm_element_value_const() hack # s390 needs -fPIC # s390-suse-linux/bin/ld: .libs/ipc.o: relocation R_390_PC32DBL against `__stack_chk_fail@@GLIBC_2.4' can not be used when making a shared object; recompile with -fPIC CFLAGS = $(CFLAGS_COPY:-Wcast-qual=) -fPIC libcrmcommon_la_LDFLAGS = -version-info 10:0:7 libcrmcommon_la_CFLAGS = $(CFLAGS_HARDENED_LIB) libcrmcommon_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB) -libcrmcommon_la_LIBADD = @LIBADD_DL@ $(GNUTLSLIBS) -lm +libcrmcommon_la_LIBADD = @LIBADD_DL@ $(GNUTLSLIBS) libcrmcommon_la_SOURCES = compat.c digest.c ipc.c io.c procfs.c utils.c xml.c \ iso8601.c remote.c mainloop.c logging.c watchdog.c \ schemas.c strings.c xpath.c attrd_client.c alerts.c if BUILD_CIBSECRETS libcrmcommon_la_SOURCES += cib_secrets.c endif libcrmcommon_la_SOURCES += $(top_builddir)/lib/gnu/md5.c clean-generic: rm -f *.log *.debug *.xml *~ diff --git a/lib/common/alerts.c b/lib/common/alerts.c index de3b241b80..471bd5339a 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -1,315 +1,291 @@ /* * Copyright (C) 2015 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include /* for F_CIB_UPDATE_RESULT */ /* * to allow script compatibility we can have more than one * set of environment variables */ const char *crm_alert_keys[CRM_ALERT_INTERNAL_KEY_MAX][3] = { [CRM_alert_recipient] = {"CRM_notify_recipient", "CRM_alert_recipient", NULL}, [CRM_alert_node] = {"CRM_notify_node", "CRM_alert_node", NULL}, [CRM_alert_nodeid] = {"CRM_notify_nodeid", "CRM_alert_nodeid", NULL}, [CRM_alert_rsc] = {"CRM_notify_rsc", "CRM_alert_rsc", NULL}, [CRM_alert_task] = {"CRM_notify_task", "CRM_alert_task", NULL}, [CRM_alert_interval] = {"CRM_notify_interval", "CRM_alert_interval", NULL}, [CRM_alert_desc] = {"CRM_notify_desc", "CRM_alert_desc", NULL}, [CRM_alert_status] = {"CRM_notify_status", "CRM_alert_status", NULL}, [CRM_alert_target_rc] = {"CRM_notify_target_rc", "CRM_alert_target_rc", NULL}, [CRM_alert_rc] = {"CRM_notify_rc", "CRM_alert_rc", NULL}, [CRM_alert_kind] = {"CRM_notify_kind", "CRM_alert_kind", NULL}, [CRM_alert_version] = {"CRM_notify_version", "CRM_alert_version", NULL}, [CRM_alert_node_sequence] = {"CRM_notify_node_sequence", CRM_ALERT_NODE_SEQUENCE, NULL}, [CRM_alert_timestamp] = {"CRM_notify_timestamp", "CRM_alert_timestamp", NULL}, [CRM_alert_attribute_name] = {"CRM_notify_attribute_name", "CRM_alert_attribute_name", NULL}, [CRM_alert_attribute_value] = {"CRM_notify_attribute_value", "CRM_alert_attribute_value", NULL} }; void crm_free_alert_envvar(crm_alert_envvar_t *entry) { free(entry->name); free(entry->value); free(entry); } /*! * \brief Create a new alert entry structure * * \param[in] id ID to use * \param[in] path Path to alert agent executable * * \return Pointer to newly allocated alert entry * \note Non-string fields will be filled in with defaults. * It is the caller's responsibility to free the result, * using crm_free_alert_entry(). */ crm_alert_entry_t * crm_alert_entry_new(const char *id, const char *path) { crm_alert_entry_t *entry = calloc(1, sizeof(crm_alert_entry_t)); CRM_ASSERT(entry && id && path); entry->id = strdup(id); entry->path = strdup(path); entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS; entry->flags = crm_alert_default; return entry; } void crm_free_alert_entry(crm_alert_entry_t *entry) { free(entry->id); free(entry->path); free(entry->tstamp_format); free(entry->recipient); if(entry->select_attribute_name) { g_strfreev(entry->select_attribute_name); } if (entry->envvars) { g_hash_table_destroy(entry->envvars); } free(entry); } crm_alert_envvar_t * crm_dup_alert_envvar(crm_alert_envvar_t *src) { crm_alert_envvar_t *dst = calloc(1, sizeof(crm_alert_envvar_t)); CRM_ASSERT(dst); dst->name = strdup(src->name); dst->value = src->value?strdup(src->value):NULL; return dst; } /*! * \internal * \brief Duplicate an alert entry * * \param[in] entry Alert entry to duplicate * * \return Duplicate of alert entry */ crm_alert_entry_t * crm_dup_alert_entry(crm_alert_entry_t *entry) { crm_alert_entry_t *new_entry = crm_alert_entry_new(entry->id, entry->path); new_entry->timeout = entry->timeout; new_entry->flags = entry->flags; new_entry->envvars = crm_str_table_dup(entry->envvars); if (entry->tstamp_format) { new_entry->tstamp_format = strdup(entry->tstamp_format); } if (entry->recipient) { new_entry->recipient = strdup(entry->recipient); } if (entry->select_attribute_name) { new_entry->select_attribute_name = g_strdupv(entry->select_attribute_name); } return new_entry; } -void -crm_set_alert_key(enum crm_alert_keys_e name, const char *value) -{ - const char **key; - - for (key = crm_alert_keys[name]; *key; key++) { - crm_trace("Setting alert key %s = '%s'", *key, value); - if (value) { - setenv(*key, value, 1); - } else { - unsetenv(*key); - } - } -} - -void -crm_set_alert_key_int(enum crm_alert_keys_e name, int value) -{ - char *s = crm_itoa(value); - - crm_set_alert_key(name, s); - free(s); -} - void crm_unset_alert_keys() { const char **key; enum crm_alert_keys_e name; for(name = 0; name < DIMOF(crm_alert_keys); name++) { for(key = crm_alert_keys[name]; *key; key++) { crm_trace("Unsetting alert key %s", *key); unsetenv(*key); } } } void crm_insert_alert_key(GHashTable *table, enum crm_alert_keys_e name, const char *value) { for (const char **key = crm_alert_keys[name]; *key; key++) { crm_trace("Inserting alert key %s = '%s'", *key, value); if (value) { g_hash_table_insert(table, strdup(*key), strdup(value)); } else { g_hash_table_remove(table, *key); } } } void crm_insert_alert_key_int(GHashTable *table, enum crm_alert_keys_e name, int value) { for (const char **key = crm_alert_keys[name]; *key; key++) { crm_trace("Inserting alert key %s = %d", *key, value); g_hash_table_insert(table, strdup(*key), crm_itoa(value)); } } static void set_envvar(gpointer key, gpointer value, gpointer user_data) { gboolean always_unset = GPOINTER_TO_INT(user_data); crm_trace("%s environment variable %s='%s'", (value? "Setting" : "Unsetting"), (char*)key, (value? (char*)value : "")); if (value && !always_unset) { setenv(key, value, 1); } else { unsetenv(key); } } void crm_set_envvar_list(crm_alert_entry_t *entry) { if (entry->envvars) { g_hash_table_foreach(entry->envvars, set_envvar, GINT_TO_POINTER(FALSE)); } } /* * \note We have no way of restoring a previous value if one was set. */ void crm_unset_envvar_list(crm_alert_entry_t *entry) { if (entry->envvars) { g_hash_table_foreach(entry->envvars, set_envvar, GINT_TO_POINTER(TRUE)); } } #define XPATH_PATCHSET1_DIFF "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED #define XPATH_PATCHSET1_CRMCONFIG XPATH_PATCHSET1_DIFF "//" XML_CIB_TAG_CRMCONFIG #define XPATH_PATCHSET1_ALERTS XPATH_PATCHSET1_DIFF "//" XML_CIB_TAG_ALERTS #define XPATH_PATCHSET1_EITHER \ XPATH_PATCHSET1_CRMCONFIG " | " XPATH_PATCHSET1_ALERTS #define XPATH_CONFIG "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION #define XPATH_CRMCONFIG XPATH_CONFIG "/" XML_CIB_TAG_CRMCONFIG "/" #define XPATH_ALERTS XPATH_CONFIG "/" XML_CIB_TAG_ALERTS /*! * \internal * \brief Check whether a CIB update affects alerts * * \param[in] msg XML containing CIB update * \param[in] config Whether to check for crmconfig change as well * * \return TRUE if update affects alerts, FALSE otherwise */ bool crm_patchset_contains_alert(xmlNode *msg, bool config) { int rc = -1; int format= 1; xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT); xmlNode *change = NULL; xmlXPathObject *xpathObj = NULL; CRM_CHECK(msg != NULL, return FALSE); crm_element_value_int(msg, F_CIB_RC, &rc); if (rc < pcmk_ok) { crm_trace("Ignore failed CIB update: %s (%d)", pcmk_strerror(rc), rc); return FALSE; } crm_element_value_int(patchset, "format", &format); if (format == 1) { const char *diff = (config? XPATH_PATCHSET1_EITHER : XPATH_PATCHSET1_ALERTS); if ((xpathObj = xpath_search(msg, diff)) != NULL) { freeXpathObject(xpathObj); return TRUE; } } else if (format == 2) { for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) { const char *xpath = crm_element_value(change, XML_DIFF_PATH); if (xpath == NULL) { continue; } if ((!config || !strstr(xpath, XPATH_CRMCONFIG)) && !strstr(xpath, XPATH_ALERTS)) { /* this is not a change to an existing section ... */ xmlNode *section = NULL; const char *name = NULL; if ((strcmp(xpath, XPATH_CONFIG) != 0) || ((section = __xml_first_child(change)) == NULL) || ((name = crm_element_name(section)) == NULL) || (strcmp(name, XML_CIB_TAG_ALERTS) != 0)) { /* ... nor is it a newly added alerts section */ continue; } } return TRUE; } } else { crm_warn("Unknown patch format: %d", format); } return FALSE; } diff --git a/lib/common/schemas.c b/lib/common/schemas.c index 77e87dc51c..b9f9d9a4fb 100644 --- a/lib/common/schemas.c +++ b/lib/common/schemas.c @@ -1,967 +1,999 @@ /* * Copyright (C) 2004-2016 Andrew Beekhof * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include -#include #include #include #if HAVE_LIBXML2 # include #endif #if HAVE_LIBXSLT # include # include # include #endif #include #include #include /* CRM_XML_LOG_BASE */ +typedef struct { + unsigned char v[2]; +} schema_version_t; + +#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]) + typedef struct { xmlRelaxNGPtr rng; xmlRelaxNGValidCtxtPtr valid; xmlRelaxNGParserCtxtPtr parser; } relaxng_ctx_cache_t; +enum schema_validator_e { + schema_validator_none, + schema_validator_dtd, + schema_validator_rng +}; + struct schema_s { - int type; - float version; char *name; char *location; char *transform; - int after_transform; void *cache; + enum schema_validator_e validator; + int after_transform; + schema_version_t version; }; static struct schema_s *known_schemas = NULL; static int xml_schema_max = 0; static void xml_log(int priority, const char *fmt, ...) G_GNUC_PRINTF(2, 3); static void xml_log(int priority, const char *fmt, ...) { va_list ap; va_start(ap, fmt); /* XXX should not this enable dechunking as well? */ CRM_XML_LOG_BASE(priority, FALSE, 0, NULL, fmt, ap); va_end(ap); } static int xml_latest_schema_index(void) { return xml_schema_max - 4; } static int xml_minimum_schema_index(void) { static int best = 0; if (best == 0) { int lpc = 0; - float target = 0.0; best = xml_latest_schema_index(); - target = floor(known_schemas[best].version); - for (lpc = best; lpc > 0; lpc--) { - if (known_schemas[lpc].version < target) { + if (known_schemas[lpc].version.v[0] + < known_schemas[best].version.v[0]) { return best; } else { best = lpc; } } best = xml_latest_schema_index(); } return best; } const char * xml_latest_schema(void) { return get_schema_name(xml_latest_schema_index()); } static const char * get_schema_root(void) { static const char *base = NULL; if (base == NULL) { base = getenv("PCMK_schema_directory"); } if (base == NULL || strlen(base) == 0) { base = CRM_DTD_DIRECTORY; } return base; } static char * get_schema_path(const char *name, const char *file) { const char *base = get_schema_root(); if (file) { return crm_strdup_printf("%s/%s", base, file); } return crm_strdup_printf("%s/%s.rng", base, name); } +static inline bool +version_from_filename(const char *filename, schema_version_t *version) +{ + int rc = schema_scanf(filename, "pacemaker-", *version, ".rng"); + + return (rc == 2); +} + static int schema_filter(const struct dirent *a) { int rc = 0; - float version = 0; + schema_version_t version = SCHEMA_ZERO; if (strstr(a->d_name, "pacemaker-") != a->d_name) { /* crm_trace("%s - wrong prefix", a->d_name); */ } else if (!crm_ends_with(a->d_name, ".rng")) { /* crm_trace("%s - wrong suffix", a->d_name); */ - } else if (sscanf(a->d_name, "pacemaker-%f.rng", &version) == 0) { + } else if (!version_from_filename(a->d_name, &version)) { /* crm_trace("%s - wrong format", a->d_name); */ } else if (strcmp(a->d_name, "pacemaker-1.1.rng") == 0) { /* "-1.1" was used for what later became "-next" */ /* crm_trace("%s - hack", a->d_name); */ } else { /* crm_debug("%s - candidate", a->d_name); */ rc = 1; } return rc; } static int schema_sort(const struct dirent **a, const struct dirent **b) { - int rc = 0; - float a_version = 0.0; - float b_version = 0.0; + schema_version_t a_version = SCHEMA_ZERO; + schema_version_t b_version = SCHEMA_ZERO; - sscanf(a[0]->d_name, "pacemaker-%f.rng", &a_version); - sscanf(b[0]->d_name, "pacemaker-%f.rng", &b_version); + version_from_filename(a[0]->d_name, &a_version); + version_from_filename(b[0]->d_name, &b_version); - if (a_version > b_version) { - rc = 1; - } else if(a_version < b_version) { - rc = -1; + for (int i = 0; i < 2; ++i) { + if (a_version.v[i] < b_version.v[i]) { + return -1; + } else if (a_version.v[i] > b_version.v[i]) { + return 1; + } } - - /* crm_trace("%s (%f) vs. %s (%f) : %d", a[0]->d_name, a_version, b[0]->d_name, b_version, rc); */ - return rc; + return 0; } static void -__xml_schema_add(int type, float version, const char *name, - const char *location, const char *transform, - int after_transform) +add_schema(enum schema_validator_e validator, const schema_version_t *version, + const char *name, const char *location, const char *transform, + int after_transform) { int last = xml_schema_max; + bool have_version = FALSE; xml_schema_max++; known_schemas = realloc_safe(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].type = type; + known_schemas[last].validator = validator; known_schemas[last].after_transform = after_transform; - if (version > 0.0) { - known_schemas[last].version = version; - known_schemas[last].name = crm_strdup_printf("pacemaker-%.1f", version); - known_schemas[last].location = crm_strdup_printf("%s.rng", known_schemas[last].name); - + for (int i = 0; i < 2; ++i) { + known_schemas[last].version.v[i] = version->v[i]; + if (version->v[i]) { + have_version = TRUE; + } + } + if (have_version) { + known_schemas[last].name = schema_strdup_printf("pacemaker-", *version, ""); + known_schemas[last].location = crm_strdup_printf("%s.rng", + known_schemas[last].name); } else { - char dummy[1024]; CRM_ASSERT(name); CRM_ASSERT(location); - sscanf(name, "%[^-]-%f", dummy, &version); - known_schemas[last].version = version; + schema_scanf(name, "%*[^-]-", known_schemas[last].version, ""); known_schemas[last].name = strdup(name); known_schemas[last].location = strdup(location); } if (transform) { known_schemas[last].transform = strdup(transform); } if (after_transform == 0) { after_transform = xml_schema_max; /* upgrade is a one-way */ } known_schemas[last].after_transform = after_transform; if (known_schemas[last].after_transform < 0) { crm_debug("Added supported schema %d: %s (%s)", last, known_schemas[last].name, known_schemas[last].location); } else if (known_schemas[last].transform) { crm_debug("Added supported schema %d: %s (%s upgrades to %d with %s)", last, known_schemas[last].name, known_schemas[last].location, known_schemas[last].after_transform, known_schemas[last].transform); } else { crm_debug("Added supported schema %d: %s (%s upgrades to %d)", last, known_schemas[last].name, known_schemas[last].location, known_schemas[last].after_transform); } } /*! * \internal * \brief Load pacemaker schemas into cache */ void crm_schema_init(void) { int lpc, max; const char *base = get_schema_root(); struct dirent **namelist = NULL; + const schema_version_t zero = SCHEMA_ZERO; max = scandir(base, &namelist, schema_filter, schema_sort); - __xml_schema_add(1, 0.0, "pacemaker-0.6", "crm.dtd", "upgrade06.xsl", 3); - __xml_schema_add(1, 0.0, "transitional-0.6", "crm-transitional.dtd", - "upgrade06.xsl", 3); - __xml_schema_add(2, 0.0, "pacemaker-0.7", "pacemaker-1.0.rng", NULL, 0); + + add_schema(schema_validator_dtd, &zero, "pacemaker-0.6", + "crm.dtd", "upgrade06.xsl", 3); + + add_schema(schema_validator_dtd, &zero, "transitional-0.6", + "crm-transitional.dtd", "upgrade06.xsl", 3); + + add_schema(schema_validator_rng, &zero, "pacemaker-0.7", + "pacemaker-1.0.rng", NULL, 0); if (max < 0) { crm_notice("scandir(%s) failed: %s (%d)", base, strerror(errno), errno); } else { for (lpc = 0; lpc < max; lpc++) { int next = 0; - float version = 0.0; + schema_version_t version = SCHEMA_ZERO; char *transform = NULL; - sscanf(namelist[lpc]->d_name, "pacemaker-%f.rng", &version); + version_from_filename(namelist[lpc]->d_name, &version); if ((lpc + 1) < max) { - float next_version = 0.0; + schema_version_t next_version = SCHEMA_ZERO; - sscanf(namelist[lpc+1]->d_name, "pacemaker-%f.rng", - &next_version); + version_from_filename(namelist[lpc+1]->d_name, &next_version); - if (floor(version) < floor(next_version)) { + if (version.v[0] < next_version.v[0]) { struct stat s; char *xslt = NULL; - transform = crm_strdup_printf("upgrade-%.1f.xsl", version); + transform = schema_strdup_printf("upgrade-", version, ".xsl"); xslt = get_schema_path(NULL, transform); if (stat(xslt, &s) != 0) { crm_err("Transform %s not found", xslt); free(xslt); - __xml_schema_add(2, version, NULL, NULL, NULL, -1); + add_schema(schema_validator_rng, &version, NULL, NULL, + NULL, -1); break; } else { free(xslt); } } } else { next = -1; } - __xml_schema_add(2, version, NULL, NULL, transform, next); + add_schema(schema_validator_rng, &version, NULL, NULL, transform, + next); free(namelist[lpc]); free(transform); } } /* 1.1 was the old name for -next */ - __xml_schema_add(2, 0.0, "pacemaker-1.1", "pacemaker-next.rng", NULL, 0); - __xml_schema_add(2, 0.0, "pacemaker-next", "pacemaker-next.rng", NULL, -1); - __xml_schema_add(0, 0.0, "none", "N/A", NULL, -1); + add_schema(schema_validator_rng, &zero, "pacemaker-1.1", + "pacemaker-next.rng", NULL, 0); + + add_schema(schema_validator_rng, &zero, "pacemaker-next", + "pacemaker-next.rng", NULL, -1); + + add_schema(schema_validator_none, &zero, "none", + "N/A", NULL, -1); free(namelist); } static gboolean validate_with_dtd(xmlDocPtr doc, gboolean to_logs, const char *dtd_file) { gboolean valid = TRUE; xmlDtdPtr dtd = NULL; xmlValidCtxtPtr cvp = NULL; CRM_CHECK(doc != NULL, return FALSE); CRM_CHECK(dtd_file != NULL, return FALSE); dtd = xmlParseDTD(NULL, (const xmlChar *)dtd_file); if (dtd == NULL) { crm_err("Could not locate/parse DTD: %s", dtd_file); return TRUE; } cvp = xmlNewValidCtxt(); if (cvp) { if (to_logs) { cvp->userData = (void *)LOG_ERR; cvp->error = (xmlValidityErrorFunc) xml_log; cvp->warning = (xmlValidityWarningFunc) xml_log; } else { cvp->userData = (void *)stderr; cvp->error = (xmlValidityErrorFunc) fprintf; cvp->warning = (xmlValidityWarningFunc) fprintf; } if (!xmlValidateDtd(cvp, doc, dtd)) { valid = FALSE; } xmlFreeValidCtxt(cvp); } else { crm_err("Internal error: No valid context"); } xmlFreeDtd(dtd); return valid; } #if 0 static void relaxng_invalid_stderr(void *userData, xmlErrorPtr error) { /* Structure xmlError struct _xmlError { int domain : What part of the library raised this er int code : The error code, e.g. an xmlParserError char * message : human-readable informative error messag xmlErrorLevel level : how consequent is the error char * file : the filename int line : the line number if available char * str1 : extra string information char * str2 : extra string information char * str3 : extra string information int int1 : extra number information int int2 : column number of the error or 0 if N/A void * ctxt : the parser context if available void * node : the node in the tree } */ crm_err("Structured error: line=%d, level=%d %s", error->line, error->level, error->message); } #endif static gboolean validate_with_relaxng(xmlDocPtr doc, gboolean to_logs, const char *relaxng_file, relaxng_ctx_cache_t **cached_ctx) { int rc = 0; gboolean valid = TRUE; relaxng_ctx_cache_t *ctx = NULL; CRM_CHECK(doc != NULL, return FALSE); CRM_CHECK(relaxng_file != NULL, return FALSE); if (cached_ctx && *cached_ctx) { ctx = *cached_ctx; } else { crm_info("Creating RNG parser context"); ctx = calloc(1, sizeof(relaxng_ctx_cache_t)); xmlLoadExtDtdDefaultValue = 1; ctx->parser = xmlRelaxNGNewParserCtxt(relaxng_file); CRM_CHECK(ctx->parser != NULL, goto cleanup); if (to_logs) { xmlRelaxNGSetParserErrors(ctx->parser, (xmlRelaxNGValidityErrorFunc) xml_log, (xmlRelaxNGValidityWarningFunc) xml_log, GUINT_TO_POINTER(LOG_ERR)); } else { xmlRelaxNGSetParserErrors(ctx->parser, (xmlRelaxNGValidityErrorFunc) fprintf, (xmlRelaxNGValidityWarningFunc) fprintf, stderr); } ctx->rng = xmlRelaxNGParse(ctx->parser); CRM_CHECK(ctx->rng != NULL, crm_err("Could not find/parse %s", relaxng_file); goto cleanup); ctx->valid = xmlRelaxNGNewValidCtxt(ctx->rng); CRM_CHECK(ctx->valid != NULL, goto cleanup); if (to_logs) { xmlRelaxNGSetValidErrors(ctx->valid, (xmlRelaxNGValidityErrorFunc) xml_log, (xmlRelaxNGValidityWarningFunc) xml_log, GUINT_TO_POINTER(LOG_ERR)); } else { xmlRelaxNGSetValidErrors(ctx->valid, (xmlRelaxNGValidityErrorFunc) fprintf, (xmlRelaxNGValidityWarningFunc) fprintf, stderr); } } /* xmlRelaxNGSetValidStructuredErrors( */ /* valid, relaxng_invalid_stderr, valid); */ xmlLineNumbersDefault(1); rc = xmlRelaxNGValidateDoc(ctx->valid, doc); if (rc > 0) { valid = FALSE; } else if (rc < 0) { crm_err("Internal libxml error during validation"); } cleanup: if (cached_ctx) { *cached_ctx = ctx; } else { if (ctx->parser != NULL) { xmlRelaxNGFreeParserCtxt(ctx->parser); } if (ctx->valid != NULL) { xmlRelaxNGFreeValidCtxt(ctx->valid); } if (ctx->rng != NULL) { xmlRelaxNGFree(ctx->rng); } free(ctx); } return valid; } /*! * \internal * \brief Clean up global memory associated with XML schemas */ 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].type) { - case 0: - /* None */ - break; - case 1: - /* DTD - Not cached */ + switch (known_schemas[lpc].validator) { + case schema_validator_none: + case schema_validator_dtd: // not cached break; - case 2: - /* RNG - Cached */ + 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; - default: - break; } free(known_schemas[lpc].name); free(known_schemas[lpc].location); free(known_schemas[lpc].transform); } free(known_schemas); known_schemas = NULL; } static gboolean validate_with(xmlNode *xml, int method, gboolean to_logs) { xmlDocPtr doc = NULL; gboolean valid = FALSE; - int type = 0; char *file = NULL; if (method < 0) { return FALSE; } - type = known_schemas[method].type; - if(type == 0) { + if (known_schemas[method].validator == schema_validator_none) { return TRUE; } CRM_CHECK(xml != NULL, return FALSE); doc = getDocPtr(xml); file = get_schema_path(known_schemas[method].name, known_schemas[method].location); - crm_trace("Validating with: %s (type=%d)", crm_str(file), type); - switch (type) { - case 1: + crm_trace("Validating with: %s (type=%d)", + crm_str(file), known_schemas[method].validator); + switch (known_schemas[method].validator) { + case schema_validator_dtd: valid = validate_with_dtd(doc, to_logs, file); break; - case 2: + case schema_validator_rng: valid = validate_with_relaxng(doc, to_logs, file, (relaxng_ctx_cache_t **) & (known_schemas[method].cache)); break; default: - crm_err("Unknown validator type: %d", type); + crm_err("Unknown validator type: %d", + known_schemas[method].validator); break; } free(file); return valid; } static void dump_file(const char *filename) { FILE *fp = NULL; int ch, line = 0; CRM_CHECK(filename != NULL, return); fp = fopen(filename, "r"); if (fp == NULL) { crm_perror(LOG_ERR, "Could not open %s for reading", filename); return; } fprintf(stderr, "%4d ", ++line); do { ch = getc(fp); if (ch == EOF) { putc('\n', stderr); break; } else if (ch == '\n') { fprintf(stderr, "\n%4d ", ++line); } else { putc(ch, stderr); } } while (1); fclose(fp); } gboolean validate_xml_verbose(xmlNode *xml_blob) { int fd = 0; xmlDoc *doc = NULL; xmlNode *xml = NULL; gboolean rc = FALSE; char *filename = strdup(CRM_STATE_DIR "/cib-invalid.XXXXXX"); CRM_CHECK(filename != NULL, return FALSE); umask(S_IWGRP | S_IWOTH | S_IROTH); fd = mkstemp(filename); write_xml_fd(xml_blob, filename, fd, FALSE); dump_file(filename); doc = xmlParseFile(filename); xml = xmlDocGetRootElement(doc); rc = validate_xml(xml, NULL, FALSE); free_xml(xml); unlink(filename); free(filename); return rc; } gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs) { int version = 0; if (validation == NULL) { validation = crm_element_value(xml_blob, XML_ATTR_VALIDATION); } if (validation == NULL) { int lpc = 0; bool valid = FALSE; /* @COMPAT pre-1.0 configs */ validation = crm_element_value(xml_blob, "ignore_dtd"); if (crm_is_true(validation)) { crm_xml_add(xml_blob, XML_ATTR_VALIDATION, "none"); return TRUE; } /* Work it out */ for (lpc = 0; lpc < xml_schema_max; lpc++) { if (validate_with(xml_blob, lpc, FALSE)) { 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) { break; } } } return valid; } version = get_schema_version(validation); if (strcmp(validation, "none") == 0) { return TRUE; } else if (version < xml_schema_max) { return validate_with(xml_blob, version, to_logs); } crm_err("Unknown validator: %s", validation); return FALSE; } #if HAVE_LIBXSLT static void cib_upgrade_err(void *ctx, const char *fmt, ...) G_GNUC_PRINTF(2, 3); static void cib_upgrade_err(void *ctx, const char *fmt, ...) { va_list ap; va_start(ap, fmt); CRM_XML_LOG_BASE(LOG_WARNING, TRUE, 0, "CIB upgrade: ", fmt, ap); va_end(ap); } static xmlNode * apply_transformation(xmlNode *xml, const char *transform, gboolean to_logs) { char *xform = NULL; xmlNode *out = NULL; xmlDocPtr res = NULL; xmlDocPtr doc = NULL; xsltStylesheet *xslt = NULL; CRM_CHECK(xml != NULL, return FALSE); doc = getDocPtr(xml); xform = get_schema_path(NULL, transform); xmlLoadExtDtdDefaultValue = 1; xmlSubstituteEntitiesDefault(1); /* for capturing, e.g., what's emitted via */ if (to_logs) { xsltSetGenericErrorFunc(NULL, cib_upgrade_err); } else { xsltSetGenericErrorFunc((void *) stderr, (xmlGenericErrorFunc) fprintf); } xslt = xsltParseStylesheetFile((const xmlChar *)xform); CRM_CHECK(xslt != NULL, goto cleanup); res = xsltApplyStylesheet(xslt, doc, NULL); CRM_CHECK(res != NULL, goto cleanup); xsltSetGenericErrorFunc(NULL, NULL); /* restore default one */ out = xmlDocGetRootElement(res); cleanup: if (xslt) { xsltFreeStylesheet(xslt); } free(xform); return out; } #endif const char * get_schema_name(int version) { if (version < 0 || version >= xml_schema_max) { return "unknown"; } return known_schemas[version].name; } int get_schema_version(const char *name) { int lpc = 0; if (name == NULL) { name = "none"; } for (; lpc < xml_schema_max; lpc++) { if (safe_str_eq(name, known_schemas[lpc].name)) { return lpc; } } return -1; } /* set which validation to use */ int update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform, gboolean to_logs) { xmlNode *xml = NULL; char *value = NULL; int max_stable_schemas = xml_latest_schema_index(); int lpc = 0, match = -1, rc = pcmk_ok; int next = -1; /* -1 denotes "inactive" value */ CRM_CHECK(best != NULL, return -EINVAL); *best = 0; CRM_CHECK(xml_blob != NULL, return -EINVAL); CRM_CHECK(*xml_blob != NULL, return -EINVAL); xml = *xml_blob; value = crm_element_value_copy(xml, XML_ATTR_VALIDATION); if (value != NULL) { match = get_schema_version(value); lpc = match; if (lpc >= 0 && transform == FALSE) { *best = lpc++; } else if (lpc < 0) { - crm_debug("Unknown validation type"); + crm_debug("Unknown validation schema"); lpc = 0; } } if (match >= max_stable_schemas) { /* nothing to do */ free(value); *best = match; return pcmk_ok; } while (lpc <= max_stable_schemas) { crm_debug("Testing '%s' validation (%d of %d)", known_schemas[lpc].name ? known_schemas[lpc].name : "", lpc, max_stable_schemas); if (validate_with(xml, lpc, to_logs) == FALSE) { if (next != -1) { crm_info("Configuration not valid for schema: %s", known_schemas[lpc].name); next = -1; } else { crm_trace("%s validation failed", known_schemas[lpc].name ? known_schemas[lpc].name : ""); } if (*best) { /* we've satisfied the validation, no need to check further */ break; } rc = -pcmk_err_schema_validation; } else { if (next != -1) { crm_debug("Configuration valid for schema: %s", known_schemas[next].name); next = -1; } rc = pcmk_ok; } if (rc == pcmk_ok) { *best = lpc; } if (rc == pcmk_ok && transform) { xmlNode *upgrade = NULL; next = known_schemas[lpc].after_transform; if (next <= lpc) { /* There is no next version, or next would regress */ crm_trace("Stopping at %s", known_schemas[lpc].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); break; } else if (known_schemas[lpc].transform == NULL) { crm_debug("%s-style configuration is also valid for %s", known_schemas[lpc].name, known_schemas[next].name); lpc = next; } else { crm_debug("Upgrading %s-style configuration to %s with %s", known_schemas[lpc].name, known_schemas[next].name, known_schemas[lpc].transform ? known_schemas[lpc].transform : "no-op"); #if HAVE_LIBXSLT upgrade = apply_transformation(xml, known_schemas[lpc].transform, to_logs); #endif if (upgrade == NULL) { crm_err("Transformation %s failed", known_schemas[lpc].transform); rc = -pcmk_err_transform_failed; } else if (validate_with(upgrade, next, to_logs)) { crm_info("Transformation %s successful", known_schemas[lpc].transform); lpc = next; *best = next; free_xml(xml); xml = upgrade; rc = pcmk_ok; } else { crm_err("Transformation %s did not produce a valid configuration", known_schemas[lpc].transform); crm_log_xml_info(upgrade, "transform:bad"); free_xml(upgrade); rc = -pcmk_err_schema_validation; } next = -1; } } if (transform == FALSE || rc != pcmk_ok) { /* we need some progress! */ lpc++; } } if (*best > match && *best) { crm_info("%s the configuration from %s to %s", transform?"Transformed":"Upgraded", value ? value : "", known_schemas[*best].name); crm_xml_add(xml, XML_ATTR_VALIDATION, known_schemas[*best].name); } *xml_blob = xml; free(value); return rc; } gboolean cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs) { gboolean rc = TRUE; const char *value = crm_element_value(*xml, XML_ATTR_VALIDATION); char *const orig_value = strdup(value == NULL ? "(none)" : value); int version = get_schema_version(value); int orig_version = version; int min_version = xml_minimum_schema_index(); if (version < min_version) { xmlNode *converted = NULL; converted = copy_xml(*xml); update_validation(&converted, &version, 0, TRUE, to_logs); value = crm_element_value(converted, XML_ATTR_VALIDATION); if (version < min_version) { if (version < orig_version || orig_version == -1) { if (to_logs) { crm_config_err("Your current configuration %s could not" " validate with any schema in range [%s, %s]," " cannot upgrade to %s.", orig_value, get_schema_name(orig_version), xml_latest_schema(), get_schema_name(min_version)); } else { fprintf(stderr, "Your current configuration %s could not" " validate with any schema in range [%s, %s]," " cannot upgrade to %s.\n", orig_value, get_schema_name(orig_version), xml_latest_schema(), get_schema_name(min_version)); } } else if (to_logs) { crm_config_err("Your current configuration could only be upgraded to %s... " "the minimum requirement is %s.", crm_str(value), get_schema_name(min_version)); } else { fprintf(stderr, "Your current configuration could only be upgraded to %s... " "the minimum requirement is %s.\n", crm_str(value), get_schema_name(min_version)); } free_xml(converted); converted = NULL; rc = FALSE; } else { free_xml(*xml); *xml = converted; if (version < xml_latest_schema_index()) { crm_config_warn("Your configuration was internally updated to %s... " "which is acceptable but not the most recent", get_schema_name(version)); } else if (to_logs) { crm_info("Your configuration was internally updated to the latest version (%s)", get_schema_name(version)); } } } else if (version >= get_schema_version("none")) { if (to_logs) { crm_config_warn("Configuration validation is currently disabled." " It is highly encouraged and prevents many common cluster issues."); } else { fprintf(stderr, "Configuration validation is currently disabled." " It is highly encouraged and prevents many common cluster issues.\n"); } } if (best_version) { *best_version = version; } free(orig_value); return rc; } diff --git a/tools/regression.validity.exp b/tools/regression.validity.exp index eac7b6e7de..d5edfe6a4b 100644 --- a/tools/regression.validity.exp +++ b/tools/regression.validity.exp @@ -1,425 +1,425 @@ Created new pacemaker configuration Setting up shadow instance A new shadow instance was created. To begin using it paste the following into your shell: CIB_shadow=tools-regression ; export CIB_shadow =#=#=#= Begin test: Try to make resulting CIB invalid (enum violation) =#=#=#= Call failed: Update does not conform to the configured schema =#=#=#= Current cib after: Try to make resulting CIB invalid (enum violation) =#=#=#= =#=#=#= End test: Try to make resulting CIB invalid (enum violation) - Update does not conform to the configured schema (203) =#=#=#= * Passed: cibadmin - Try to make resulting CIB invalid (enum violation) =#=#=#= Begin test: Run crm_simulate with invalid CIB (enum violation) =#=#=#= ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-1.2' validation (4 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-1.2 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-1.3' validation (5 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-1.3 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.0' validation (6 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.0 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.1' validation (7 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.1 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.2' validation (8 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.2 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.3' validation (9 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.3 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.4' validation (10 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.4 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.5' validation (11 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.5 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.6' validation (12 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.6 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.7' validation (13 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.7 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.8' validation (14 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.8 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.9' validation (15 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 ( schemas.c:NNN ) trace: update_validation: pacemaker-2.9 validation failed Your current configuration pacemaker-1.2 could not validate with any schema in range [pacemaker-1.2, pacemaker-2.9], cannot upgrade to pacemaker-2.0. =#=#=#= End test: Run crm_simulate with invalid CIB (enum violation) - Required key not available (126) =#=#=#= * Passed: crm_simulate - Run crm_simulate with invalid CIB (enum violation) =#=#=#= Begin test: Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#= Call failed: Update does not conform to the configured schema =#=#=#= Current cib after: Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#= =#=#=#= End test: Try to make resulting CIB invalid (unrecognized validate-with) - Update does not conform to the configured schema (203) =#=#=#= * Passed: cibadmin - Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#= Begin test: Run crm_simulate with invalid CIB (unrecognized validate-with) =#=#=#= -( schemas.c:NNN ) debug: update_validation: Unknown validation type +( schemas.c:NNN ) debug: update_validation: Unknown validation schema ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-0.6' validation (0 of X) element rsc_order: validity error : Element rsc_order does not carry attribute to element rsc_order: validity error : Element rsc_order does not carry attribute from element rsc_order: validity error : No declaration for attribute first of element rsc_order element rsc_order: validity error : No declaration for attribute first-action of element rsc_order element rsc_order: validity error : No declaration for attribute then of element rsc_order ( schemas.c:NNN ) trace: update_validation: pacemaker-0.6 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'transitional-0.6' validation (1 of X) element rsc_order: validity error : Element rsc_order does not carry attribute to element rsc_order: validity error : Element rsc_order does not carry attribute from element rsc_order: validity error : No declaration for attribute first of element rsc_order element rsc_order: validity error : No declaration for attribute first-action of element rsc_order element rsc_order: validity error : No declaration for attribute then of element rsc_order ( schemas.c:NNN ) trace: update_validation: transitional-0.6 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-0.7' validation (2 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-0.7 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-1.0' validation (3 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-1.0 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-1.2' validation (4 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-1.2 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-1.3' validation (5 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-1.3 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.0' validation (6 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.0 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.1' validation (7 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.1 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.2' validation (8 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.2 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.3' validation (9 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.3 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.4' validation (10 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.4 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.5' validation (11 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.5 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.6' validation (12 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.6 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.7' validation (13 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.7 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.8' validation (14 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.8 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.9' validation (15 of X) element cib: Relax-NG validity error : Invalid attribute validate-with for element cib ( schemas.c:NNN ) trace: update_validation: pacemaker-2.9 validation failed Your current configuration pacemaker-9999.0 could not validate with any schema in range [unknown, pacemaker-2.9], cannot upgrade to pacemaker-2.0. =#=#=#= End test: Run crm_simulate with invalid CIB (unrecognized validate-with) - Required key not available (126) =#=#=#= * 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) =#=#=#= Call failed: Update does not conform to the configured schema =#=#=#= Current cib after: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) =#=#=#= =#=#=#= End test: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) - Update does not conform to the configured schema (203) =#=#=#= * Passed: cibadmin - Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) =#=#=#= Begin test: Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1) =#=#=#= ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-1.2' validation (4 of X) element tags: Relax-NG validity error : Element configuration has extra content: tags ( schemas.c:NNN ) trace: update_validation: pacemaker-1.2 validation failed ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-1.3' validation (5 of X) ( schemas.c:NNN ) debug: update_validation: Upgrading pacemaker-1.3-style configuration to pacemaker-2.0 with upgrade-1.3.xsl ( schemas.c:NNN ) info: update_validation: Transformation upgrade-1.3.xsl successful ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.0' validation (6 of X) ( schemas.c:NNN ) debug: update_validation: pacemaker-2.0-style configuration is also valid for pacemaker-2.1 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.1' validation (7 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.1 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.1-style configuration is also valid for pacemaker-2.2 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.2' validation (8 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.2 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.2-style configuration is also valid for pacemaker-2.3 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.3' validation (9 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.3 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.3-style configuration is also valid for pacemaker-2.4 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.4' validation (10 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.4 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.4-style configuration is also valid for pacemaker-2.5 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.5' validation (11 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.5 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.5-style configuration is also valid for pacemaker-2.6 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.6' validation (12 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.6 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.6-style configuration is also valid for pacemaker-2.7 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.7' validation (13 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.7 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.7-style configuration is also valid for pacemaker-2.8 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.8' validation (14 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.8 ( schemas.c:NNN ) debug: update_validation: pacemaker-2.8-style configuration is also valid for pacemaker-2.9 ( schemas.c:NNN ) debug: update_validation: Testing 'pacemaker-2.9' validation (15 of X) ( schemas.c:NNN ) debug: update_validation: Configuration valid for schema: pacemaker-2.9 ( schemas.c:NNN ) trace: update_validation: Stopping at pacemaker-2.9 ( schemas.c:NNN ) info: update_validation: Transformed the configuration from pacemaker-1.2 to pacemaker-2.9 error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity Current cluster status: dummy1 (ocf::pacemaker:Dummy): Stopped dummy2 (ocf::pacemaker:Dummy): Stopped Transition Summary: error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity Executing cluster transition: Revised cluster status: dummy1 (ocf::pacemaker:Dummy): Stopped dummy2 (ocf::pacemaker:Dummy): Stopped =#=#=#= End test: Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1) - OK (0) =#=#=#= * Passed: crm_simulate - Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1) =#=#=#= Begin test: Make resulting CIB valid, although without validate-with attribute =#=#=#= element rsc_order: validity error : Element rsc_order does not carry attribute to element rsc_order: validity error : Element rsc_order does not carry attribute from element rsc_order: validity error : No declaration for attribute first of element rsc_order element rsc_order: validity error : No declaration for attribute first-action of element rsc_order element rsc_order: validity error : No declaration for attribute then of element rsc_order element rsc_order: validity error : Element rsc_order does not carry attribute to element rsc_order: validity error : Element rsc_order does not carry attribute from element rsc_order: validity error : No declaration for attribute first of element rsc_order element rsc_order: validity error : No declaration for attribute first-action of element rsc_order element rsc_order: validity error : No declaration for attribute then of element rsc_order =#=#=#= Current cib after: Make resulting CIB valid, although without validate-with attribute =#=#=#= =#=#=#= End test: Make resulting CIB valid, although without validate-with attribute - OK (0) =#=#=#= * Passed: cibadmin - Make resulting CIB valid, although without validate-with attribute =#=#=#= Begin test: Run crm_simulate with valid CIB, but without validate-with attribute =#=#=#= Configuration validation is currently disabled. It is highly encouraged and prevents many common cluster issues. bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute to bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute from bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first-action of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute then of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute to bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute from bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first-action of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute then of element rsc_order error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity Current cluster status: dummy1 (ocf::pacemaker:Dummy): Stopped dummy2 (ocf::pacemaker:Dummy): Stopped Transition Summary: error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity Executing cluster transition: Revised cluster status: dummy1 (ocf::pacemaker:Dummy): Stopped dummy2 (ocf::pacemaker:Dummy): Stopped =#=#=#= End test: Run crm_simulate with valid CIB, but without validate-with attribute - OK (0) =#=#=#= * Passed: crm_simulate - Run crm_simulate with valid CIB, but without validate-with attribute =#=#=#= Begin test: Make resulting CIB invalid, and without validate-with attribute =#=#=#= element rsc_order: validity error : Element rsc_order does not carry attribute to element rsc_order: validity error : Element rsc_order does not carry attribute from element rsc_order: validity error : No declaration for attribute first of element rsc_order element rsc_order: validity error : No declaration for attribute first-action of element rsc_order element rsc_order: validity error : No declaration for attribute then of element rsc_order element rsc_order: validity error : Element rsc_order does not carry attribute to element rsc_order: validity error : Element rsc_order does not carry attribute from element rsc_order: validity error : No declaration for attribute first of element rsc_order element rsc_order: validity error : No declaration for attribute first-action of element rsc_order element rsc_order: validity error : No declaration for attribute then of element 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 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 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 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 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 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 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 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 =#=#=#= =#=#=#= End test: Make resulting CIB invalid, and without validate-with attribute - OK (0) =#=#=#= * Passed: cibadmin - Make resulting CIB invalid, and without validate-with attribute =#=#=#= Begin test: Run crm_simulate with invalid CIB, also without validate-with attribute =#=#=#= Configuration validation is currently disabled. It is highly encouraged and prevents many common cluster issues. bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute to bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute from bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first-action of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute then of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute to bad-1.2.xml:10: element rsc_order: validity error : Element rsc_order does not carry attribute from bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute first-action of element rsc_order bad-1.2.xml:10: element rsc_order: validity error : No declaration for attribute then of element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order bad-1.2.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity (constraints.:430 ) error: unpack_simple_rsc_order: Cannot invert rsc_order constraint ord_1-2. Please specify the inverse manually. Current cluster status: dummy1 (ocf::pacemaker:Dummy): Stopped dummy2 (ocf::pacemaker:Dummy): Stopped Transition Summary: error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity Executing cluster transition: Revised cluster status: dummy1 (ocf::pacemaker:Dummy): Stopped dummy2 (ocf::pacemaker:Dummy): Stopped =#=#=#= End test: Run crm_simulate with invalid CIB, also without validate-with attribute - OK (0) =#=#=#= * Passed: crm_simulate - Run crm_simulate with invalid CIB, also without validate-with attribute diff --git a/xml/Readme.md b/xml/Readme.md index bdefad14f6..e0308c0aed 100644 --- a/xml/Readme.md +++ b/xml/Readme.md @@ -1,86 +1,86 @@ # Schema Reference Besides the version of Pacemaker itself, the XML schema of the Pacemaker configuration has its own version. ## Versioned Schema Evolution A versioned schema offers transparent backward/forward compatibility. - It reflects the timeline of schema-backed features (introduction, changes to the syntax, possibly deprecation) through the versioned stable schema increments, while keeping schema versions used by default by older Pacemaker versions untouched. - Pacemaker internally uses the latest stable schema version, and relies on supplemental transformations to promote cluster configurations based on older, incompatible schema versions into the desired form. - It allows experimental features with a possibly unstable configuration interface to be developed using the special `next` version of the schema. ## Mapping Pacemaker Versions to Schema Versions | Pacemaker | Latest Schema | Changed | --------- | ------------- | ---------------------------------------------- | `1.1.17` | `2.9` | `resources`, `rule` | `1.1.16` | `2.6` | `constraints` | `1.1.15` | `2.5` | `alerts` | `1.1.14` | `2.4` | `fencing` | `1.1.13` | `2.3` | `constraints` | `1.1.12` | `2.0` | `nodes`, `nvset`, `resources`, `tags` + `acls` | `1.1.8`+ | `1.2` | # Updating schema files # ## Experimental features ## Experimental features go into `${base}-next.rng` Create from the most recent `${base}-${X}.${Y}.rng` if it does not already exist ## Stable features ## The current stable version is determined at runtime when -__xml_build_schema_list() interrogates the CRM_DTD_DIRECTORY. +crm_schema_init() scans the CRM_DTD_DIRECTORY. It will have the form `pacemaker-${X}.${Y}` and the highest `${X}.${Y}` wins. ### Simple Additions When the new syntax is a simple addition to the previous one, create a new entry with `${Y} = ${Yold} + 1` ### Feature Removal or otherwise Incompatible Changes When the new syntax is not a simple addition to the previous one, create a new entry with `${X} = ${Xold} + 1` and `${Y} = 0`. An XSLT file is also required that converts an old syntax to the new one and must be named `upgrade-${Xold}.${Yold}.xsl`. See `xml/upgrade06.xsl` for an example. ### General Procedure 1. Copy the most recent version of `${base}-*.rng` to `${base}-${X}.${Y}.rng` 1. Commit the copy, eg. `"Clone the latest ${base} schema in preparation for changes"`. This way the actual change will be obvious in the commit history. 1. Modify `${base}-${X}.${Y}.rng` as required 1. Add an XSLT file if required and update `xslt_SCRIPTS` in `xml/Makefile.am` 1. Commit ## Admin Tasks New features will not be available until the admin 1. Updates all the nodes -1. Runs the equivalent of `cibadmin --upgrade` +1. Runs the equivalent of `cibadmin --upgrade --force` ## Random Notes From the source directory, run `make -C xml diff` to see the changes in the current schema (compared to the previous ones) and also the pending changes in `pacemaker-next`. Alternatively, if the intention is to grok the overall historical schema evolution, use `make -C xml fulldiff`.