osaf/tools/safimm/immcfg/imm_cfg.c | 31 ++++- osaf/tools/safimm/immcfg/imm_import.cc | 178 ++++++++++++++++++++++++++++++- osaf/tools/safimm/immlist/imm_list.c | 6 - osaf/tools/safimm/immload/imm_loader.cc | 150 +++++++++++++++++++++++++- 4 files changed, 333 insertions(+), 32 deletions(-)
For forwards compatibility, OpenSAF schema, where unknown attribute flags are defined, must be provided to immcfg using -X flag. If immload finds unknown attribute flag, immload will try to find the attribute flag in the schema defined in the top element of the loading IMM XML file. diff --git a/osaf/tools/safimm/immcfg/imm_cfg.c b/osaf/tools/safimm/immcfg/imm_cfg.c --- a/osaf/tools/safimm/immcfg/imm_cfg.c +++ b/osaf/tools/safimm/immcfg/imm_cfg.c @@ -56,7 +56,7 @@ typedef enum { #define VERBOSE_INFO(format, args...) if (verbose) { fprintf(stderr, format, ##args); } // The interface function which implements the -f opton (imm_import.cc) -int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe); +int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, const char *xsdPath); const SaImmCcbFlagsT defCcbFlags = SA_IMM_CCB_REGISTERED_OI | SA_IMM_CCB_ALLOW_NULL_OI; @@ -86,6 +86,7 @@ static void usage(const char *progname) printf("\t--ignore-duplicates (only valid with -f/--file option, default)\n"); printf("\t--delete-class <classname> [classname2]... \n"); printf("\t-u, --unsafe\n"); + printf("\t-X, --xsd <path_to_schema.xsd>\n"); printf("\nEXAMPLE\n"); printf("\timmcfg -a saAmfNodeSuFailoverMax=7 safAmfNode=Node01,safAmfCluster=1\n"); @@ -102,6 +103,10 @@ static void usage(const char *progname) printf("\t\tremove a value from an attribute\n"); printf("\timmcfg -u .....\n"); printf("\t\tThe CCBs generated by immcfg will have SA_IMM_CCB_REGISTERED_OI set to false, allowing ccb commit when OIs are missing\n"); + printf("\timmcfg -X /etc/opensaf/schema.xsd -f imm.xml\n"); + printf("\t\timmcfg will load unsupported attribute flags in the current OpenSAF version from /etc/opensaf/schema.xsd, and use them to successfully import imm.xml"); + printf("\timmcfg -X /etc/opensaf -f imm.xml\n"); + printf("\t\timmcfg will load unsupported attribute flags in the current OpenSAF version from the schema specified in imm.xml which is stored in /etc/opensaf, and use loaded flags to successfully import imm.xml"); } /* signal handler for SIGALRM */ @@ -682,6 +687,7 @@ int main(int argc, char *argv[]) {"timeout", required_argument, NULL, 't'}, {"verbose", no_argument, NULL, 'v'}, {"unsafe", no_argument, NULL, 'u'}, + {"xsd", required_argument, NULL, 'X'}, {0, 0, 0, 0} }; SaAisErrorT error; @@ -703,9 +709,11 @@ int main(int argc, char *argv[]) int i; unsigned long timeoutVal = 60; + char *xsdPath = NULL; + while (1) { int option_index = 0; - c = getopt_long(argc, argv, "a:c:f:t:dhmvu", long_options, &option_index); + c = getopt_long(argc, argv, "a:c:f:t:dhmvuX:", long_options, &option_index); if (c == -1) /* have all command-line options have been parsed? */ break; @@ -751,6 +759,13 @@ int main(int argc, char *argv[]) op = verify_setoption(op, MODIFY_OBJECT); break; } + case 'X': + if(xsdPath) { + fprintf(stderr, "XSD path is already set\n"); + exit(EXIT_FAILURE); + } + xsdPath = strdup(optarg); + break; default: fprintf(stderr, "Try '%s --help' for more information\n", argv[0]); exit(EXIT_FAILURE); @@ -767,7 +782,7 @@ int main(int argc, char *argv[]) if (op == LOAD_IMMFILE) { VERBOSE_INFO("importImmXML(xmlFilename=%s, verbose=%d)\n", xmlFilename, verbose); - rc = importImmXML(xmlFilename, adminOwnerName, verbose, ccb_safe); + rc = importImmXML(xmlFilename, adminOwnerName, verbose, ccb_safe, xsdPath); exit(rc); } @@ -854,10 +869,14 @@ int main(int argc, char *argv[]) done_om_finalize: error = immutil_saImmOmFinalize(immHandle); if (SA_AIS_OK != error) { - fprintf(stderr, "error - saImmOmFinalize FAILED: %s\n", saf_error(error)); - rc = EXIT_FAILURE; - } + fprintf(stderr, "error - saImmOmFinalize FAILED: %s\n", saf_error(error)); + rc = EXIT_FAILURE; + } + if(xsdPath) { + free(xsdPath); + xsdPath = NULL; + } exit(rc); } diff --git a/osaf/tools/safimm/immcfg/imm_import.cc b/osaf/tools/safimm/immcfg/imm_import.cc --- a/osaf/tools/safimm/immcfg/imm_import.cc +++ b/osaf/tools/safimm/immcfg/imm_import.cc @@ -21,6 +21,8 @@ #include <set> #include <string> #include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> #include <string.h> #include <stdio.h> #include <stdlib.h> @@ -28,16 +30,14 @@ #include <assert.h> #include <syslog.h> #include <configmake.h> +#include <sys/stat.h> +#include <errno.h> #include <saAis.h> #include <saImmOm.h> #include <immutil.h> -#ifndef SA_IMM_ATTR_NO_DUPLICATES -#define SA_IMM_ATTR_NO_DUPLICATES 0x0000000001000000 /* See: http://devel.opensaf.org/ticket/1545 */ -#endif - #ifndef SA_IMM_ATTR_NOTIFY #define SA_IMM_ATTR_NOTIFY 0x0000000002000000 /* See: http://devel.opensaf.org/ticket/2883 */ #endif @@ -68,7 +68,7 @@ static char base64_dec_table[] = { extern "C" { - int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe); + int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, const char *xsdPath); } extern ImmutilErrorFnT immutilError; @@ -141,6 +141,11 @@ typedef struct ParserStateStruct { SaImmHandleT ccbHandle; } ParserState; +bool isXsdLoaded = false; +static const char *imm_xsd_file; +typedef std::set<std::string> AttrFlagSet; +AttrFlagSet attrFlagSet; + /* Prototypes */ @@ -1001,6 +1006,143 @@ static inline bool isBase64Encoded(const return isB64; } +static inline char *getAttrValue(xmlAttributePtr attr) { + if(!attr || !attr->children) { + return NULL; + } + + return (char *)attr->children->content; +} + +static bool loadXsd(const xmlChar** attrs) { + if(!imm_xsd_file) { + return true; + } + + // Check if schema path exist + struct stat st; + if(stat(imm_xsd_file, &st)) { + if(errno == ENOENT) { + LOG_ER("%s does not exist", imm_xsd_file); + } else { + LOG_ER("stat of %s return error: %d", imm_xsd_file, errno); + } + + return false; + } + // It should be a file or a directory + if(!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { + LOG_ER("%s is not a file or directory", imm_xsd_file); + return false; + } + + std::string xsdFile = imm_xsd_file; + if(S_ISDIR(st.st_mode)) { + // Schema path is a directory, so we shall add a schema file from XML file + if(xsdFile.at(xsdFile.size() - 1) != '/') { + xsdFile.append("/"); + } + char *xsd = (char *)getAttributeValue(attrs, (xmlChar *)"noNamespaceSchemaLocation"); + if(!xsd) { + // try with a namespace + xsd = (char *)getAttributeValue(attrs, (xmlChar *)"xsi:noNamespaceSchemaLocation"); + if(!xsd) { + LOG_ER("Schema is not defined in XML file"); + return false; + } + } + xsdFile.append(xsd); + + // Check if schema file exists and that it's a file + if(stat(xsdFile.c_str(), &st)) { + if(errno == ENOENT) { + LOG_ER("XSD file %s does not exist", imm_xsd_file); + } else { + LOG_ER("Stat of XSD file %s return error: %d", imm_xsd_file, errno); + } + + return false; + } + if(!S_ISREG(st.st_mode)) { + LOG_ER("Schema %s is not a file", xsdFile.c_str()); + return false; + } + } + + xmlNodePtr xsdDocRoot; + xmlDocPtr xsdDoc = xmlParseFile(xsdFile.c_str()); + if(!xsdDoc) { + return false; + } + + bool rc = true; + xmlXPathContextPtr ctx = xmlXPathNewContext(xsdDoc); + if(!ctx) { + rc = false; + goto freedoc; + } + + // Add namespace of the first element + xsdDocRoot = xmlDocGetRootElement(xsdDoc); + if(xsdDocRoot->ns) { + ctx->namespaces = (xmlNsPtr *)malloc(sizeof(xmlNsPtr)); + ctx->namespaces[0] = xsdDocRoot->ns; + ctx->nsNr = 1; + } + + xmlXPathObjectPtr xpathObj; + xpathObj = xmlXPathEval((const xmlChar*)"/xs:schema/xs:simpleType[@name=\"attr-flags\"]/xs:restriction/xs:enumeration", ctx); + if(!xpathObj || !xpathObj->nodesetval) { + rc = false; + goto freectx; + } + + xmlElementPtr element; + xmlAttributePtr attr; + char *value; + int size; + + size = xpathObj->nodesetval->nodeNr; + for(int i=0; i<size; i++) { + value = NULL; + element = (xmlElementPtr)xpathObj->nodesetval->nodeTab[i]; + attr = element->attributes; + while(attr) { + if(!strcmp((char *)attr->name, "value")) { + value = getAttrValue(attr); + } + + if(value) { + break; + } + + attr = (xmlAttributePtr)attr->next; + } + + if(value) { + if(strcmp(value, "SA_RUNTIME") && strcmp(value, "SA_CONFIG") && + strcmp(value, "SA_MULTI_VALUE") && strcmp(value, "SA_WRITABLE") && + strcmp(value, "SA_INITIALIZED") && strcmp(value, "SA_PERSISTENT") && + strcmp(value, "SA_CACHED") && strcmp(value, "SA_NOTIFY")) { + attrFlagSet.insert(value); + } + } + } + + isXsdLoaded = true; + + xmlXPathFreeObject(xpathObj); +freectx: + if(ctx->nsNr) { + free(ctx->namespaces); + } + xmlXPathFreeContext(ctx); +freedoc: + xmlFreeDoc(xsdDoc); + + return rc; +} + /** * This is the handler for start tags */ @@ -1125,6 +1267,12 @@ static void startElementHandler(void* us /* <imm:IMM-contents> */ } else if (strcmp((const char*)name, "imm:IMM-contents") == 0) { state->state[state->depth] = IMM_CONTENTS; + if(imm_xsd_file) { + if(!loadXsd(attrs)) { + LOG_ER("Failed to load XML schema", name); + exit(1); + } + } } else { LOG_ER("UNKNOWN TAG! (%s)", name); exit(1); @@ -1562,15 +1710,21 @@ static SaImmAttrFlagsT charsToFlagsHelpe return SA_IMM_ATTR_PERSISTENT; } else if (len == strlen("SA_CACHED") && strncmp((const char*)str, "SA_CACHED", len) == 0) { return SA_IMM_ATTR_CACHED; - } else if (len == strlen("SA_NO_DUPLICATES") && strncmp((const char*)str, "SA_NO_DUPLICATES", len) == 0) { - return SA_IMM_ATTR_NO_DUPLICATES; } else if (len == strlen("SA_NOTIFY") && strncmp((const char*)str, "SA_NOTIFY", len) == 0) { return SA_IMM_ATTR_NOTIFY; } - LOG_ER("UNKNOWN FLAGS, %s", str); + std::string flag((char *)str, len); + if(isXsdLoaded) { + AttrFlagSet::iterator it = attrFlagSet.find(flag); + if(it != attrFlagSet.end()) { + return 0; + } + } - exit(1); + LOG_ER("UNKNOWN FLAGS, %s", flag.c_str()); + + exit(1); } /** @@ -2036,7 +2190,7 @@ int loadImmXML(std::string xmlfile) // C and c++ caller wrapper // The objective is to keep the code copied from imm_load.cc as close to original as possible // to ease a future refactoring towards common codebase -int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe) +int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, const char *xsdPath) { std::string xmlfile(xmlfileC); imm_import_adminOwnerName = adminOwnerName; @@ -2044,6 +2198,10 @@ int importImmXML(char* xmlfileC, char* a imm_import_ccb_safe = ccb_safe; LOG_IN("file: %s adminOwner: %s", xmlfileC, adminOwnerName); + imm_xsd_file = xsdPath; + isXsdLoaded = false; + attrFlagSet.clear(); + // assign own immutil errorhandler (no call to abort()) immutilError = imm_importImmutilError; diff --git a/osaf/tools/safimm/immlist/imm_list.c b/osaf/tools/safimm/immlist/imm_list.c --- a/osaf/tools/safimm/immlist/imm_list.c +++ b/osaf/tools/safimm/immlist/imm_list.c @@ -324,9 +324,6 @@ static void display_class_definition(con if (attrDefinition->attrFlags & SA_IMM_ATTR_NOTIFY) printf(", NOTIFY"); - if (attrDefinition->attrFlags & SA_IMM_ATTR_NO_DUPLICATES) - printf(", NO_DUPLICATES"); - } else if (attrDefinition->attrFlags & SA_IMM_ATTR_RUNTIME) { if (attrDefinition->attrDefaultValue != NULL) { printf(" = "); @@ -348,9 +345,6 @@ static void display_class_definition(con if (attrDefinition->attrFlags & SA_IMM_ATTR_NOTIFY) printf(", NOTIFY"); - - if (attrDefinition->attrFlags & SA_IMM_ATTR_NO_DUPLICATES) - printf(", NO_DUPLICATES"); } printf("}\n"); diff --git a/osaf/tools/safimm/immload/imm_loader.cc b/osaf/tools/safimm/immload/imm_loader.cc --- a/osaf/tools/safimm/immload/imm_loader.cc +++ b/osaf/tools/safimm/immload/imm_loader.cc @@ -17,7 +17,9 @@ #include "imm_loader.hh" #include <iostream> +#include <set> #include <libxml/parser.h> +#include <libxml/xpath.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -26,11 +28,8 @@ #include <configmake.h> #include <logtrace.h> #include <sys/stat.h> - - -#ifndef SA_IMM_ATTR_NO_DUPLICATES -#define SA_IMM_ATTR_NO_DUPLICATES 0x0000000001000000 /* See: http://devel.opensaf.org/ticket/1545 */ -#endif +#include <errno.h> + #ifndef SA_IMM_ATTR_NOTIFY #define SA_IMM_ATTR_NOTIFY 0x0000000002000000 /* See: http://devel.opensaf.org/ticket/2883 */ @@ -121,6 +120,13 @@ typedef struct ParserStateStruct SaImmHandleT ccbHandle; } ParserState; +bool isXsdLoaded; +std::string xsddir; +std::string xsd; +typedef std::set<std::string> AttrFlagSet; +AttrFlagSet attrFlagSet; + + /* Helper functions */ static void addToAttrTypeCache(ParserState*, SaImmValueTypeT); @@ -884,6 +890,13 @@ static void startElementHandler(void* us else if (strcmp((const char*)name, "imm:IMM-contents") == 0) { state->state[state->depth] = IMM_CONTENTS; + char *schema = (char *)getAttributeValue(attrs, (xmlChar *)"noNamespaceSchemaLocation"); + if(!schema) { + schema = (char *)getAttributeValue(attrs, (xmlChar *)"xsi:noNamespaceSchemaLocation"); + } + if(schema) { + xsd = schema; + } } else { @@ -1426,6 +1439,105 @@ static xmlEntityPtr return xmlGetPredefinedEntity(name); } +static inline char *getAttrValue(xmlAttributePtr attr) { + if(!attr || !attr->children) { + return NULL; + } + + return (char *)attr->children->content; +} + +static bool loadXsd(const char *xsdFile) { + struct stat st; + if(stat(xsdFile, &st)) { + if(errno == ENOENT) { + LOG_ER("%s does not exist", xsdFile); + } else { + LOG_ER("stat of %s return error: %d", xsdFile, errno); + } + + return false; + } + // It should be a file or a directory + if(!S_ISREG(st.st_mode)) { + LOG_ER("%s is not a file", xsdFile); + return false; + } + + xmlNodePtr xsdDocRoot; + xmlDocPtr xsdDoc = xmlParseFile(xsdFile); + if(!xsdDoc) { + return false; + } + + bool rc = true; + xmlXPathContextPtr ctx = xmlXPathNewContext(xsdDoc); + if(!ctx) { + rc = false; + goto freedoc; + } + + // Add namespace of the first element + xsdDocRoot = xmlDocGetRootElement(xsdDoc); + if(xsdDocRoot->ns) { + ctx->namespaces = (xmlNsPtr *)malloc(sizeof(xmlNsPtr)); + ctx->namespaces[0] = xsdDocRoot->ns; + ctx->nsNr = 1; + } + + xmlXPathObjectPtr xpathObj; + xpathObj = xmlXPathEval((const xmlChar*)"/xs:schema/xs:simpleType[@name=\"attr-flags\"]/xs:restriction/xs:enumeration", ctx); + if(!xpathObj || !xpathObj->nodesetval) { + rc = false; + goto freectx; + } + + xmlElementPtr element; + xmlAttributePtr attr; + char *value; + int size; + + size = xpathObj->nodesetval->nodeNr; + for(int i=0; i<size; i++) { + value = NULL; + element = (xmlElementPtr)xpathObj->nodesetval->nodeTab[i]; + attr = element->attributes; + while(attr) { + if(!strcmp((char *)attr->name, "value")) { + value = getAttrValue(attr); + } + + if(value) { + break; + } + + attr = (xmlAttributePtr)attr->next; + } + + if(value) { + if(strcmp(value, "SA_RUNTIME") && strcmp(value, "SA_CONFIG") && + strcmp(value, "SA_MULTI_VALUE") && strcmp(value, "SA_WRITABLE") && + strcmp(value, "SA_INITIALIZED") && strcmp(value, "SA_PERSISTENT") && + strcmp(value, "SA_CACHED") && strcmp(value, "SA_NOTIFY")) { + attrFlagSet.insert(value); + } + } + } + + isXsdLoaded = true; + + xmlXPathFreeObject(xpathObj); +freectx: + if(ctx->nsNr) { + free(ctx->namespaces); + } + xmlXPathFreeContext(ctx); +freedoc: + xmlFreeDoc(xsdDoc); + + return rc; +} + /** * Takes a string and returns the corresponding flag */ @@ -1463,16 +1575,29 @@ static SaImmAttrFlagsT charsToFlagsHelpe { return SA_IMM_ATTR_CACHED; } - else if (len == strlen("SA_NO_DUPLICATES") && strncmp((const char*)str, "SA_NO_DUPLICATES", len) == 0) - { - return SA_IMM_ATTR_NO_DUPLICATES; - } else if (len == strlen("SA_NOTIFY") && strncmp((const char*)str, "SA_NOTIFY", len) == 0) { return SA_IMM_ATTR_NOTIFY; } - LOG_ER("UNKNOWN FLAGS, %s", str); + std::string unflag((char *)str, len); + if(!isXsdLoaded) { + std::string xsdPath = xsddir; + if(xsdPath.size() > 0) + xsdPath.append("/"); + xsdPath.append(xsd); + LOG_WA("Found unknown flag (%s). Trying to load a schema %s", unflag.c_str(), xsdPath.c_str()); + loadXsd(xsdPath.c_str()); + } + + if(isXsdLoaded) { + AttrFlagSet::iterator it = attrFlagSet.find(unflag); + if(it != attrFlagSet.end()) { + return 0; + } + } + + LOG_ER("UNKNOWN FLAGS, %s", unflag.c_str()); exit(1); } @@ -1881,6 +2006,11 @@ int loadImmXML(std::string xmldir, std:: state.adminInit = 0; state.ccbInit = 0; + isXsdLoaded = false; + xsddir = xmldir; + xsd = ""; + attrFlagSet.clear(); + /* Build the filename */ filename = xmldir; filename.append("/"); ------------------------------------------------------------------------------ Managing the Performance of Cloud-Based Applications Take advantage of what the Cloud has to offer - Avoid Common Pitfalls. Read the Whitepaper. http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel