osaf/tools/safimm/immcfg/imm_cfg.c | 29 ++++- osaf/tools/safimm/immcfg/imm_import.cc | 191 ++++++++++++++++++++++++++++++-- 2 files changed, 200 insertions(+), 20 deletions(-)
For forwards compatibility, OpenSAF schema, where unknown attribute flags are defined, must be provided to immcfg using -X flag. 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 @@ -80,7 +80,8 @@ typedef enum { // Interface functions which implement -f and -L options (imm_import.cc) int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, - SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle, SaImmCcbHandleT *ccbHandle, int mode); + SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle, + SaImmCcbHandleT *ccbHandle, int mode, const char *xsdPath); int validateImmXML(const char *xmlfile, int verbose, int mode); static int imm_operation(int argc, char *argv[]); @@ -129,6 +130,7 @@ static void usage(const char *progname) printf("\t--admin-owner-clear\n"); printf("\t--ccb-apply (only in a transaction mode)\n"); printf("\t--ccb-abort (only in a transaction mode)\n"); + printf("\t-X, --xsd <path_to_schema.xsd>\n"); printf("\nEXAMPLE\n"); printf("\timmcfg -a saAmfNodeSuFailoverMax=7 safAmfNode=Node01,safAmfCluster=1\n"); @@ -160,6 +162,10 @@ static void usage(const char *progname) printf("\timmcfg\n"); printf("\t\tRunning immcfg in explicit commit mode where immcfg accepts immcfg commands from command line\n"); printf("\t\tCtrl+D - commit changes and exit, Ctrl+C - abort CCB and exit\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 */ @@ -1093,6 +1099,7 @@ static int imm_operation(int argc, char {"admin-owner-clear", no_argument, NULL, 0}, {"ccb-apply", no_argument, NULL, 0}, {"ccb-abort", no_argument, NULL, 0}, + {"xsd", required_argument, NULL, 'X'}, {0, 0, 0, 0} }; SaAisErrorT error; @@ -1115,9 +1122,11 @@ static int imm_operation(int argc, char unsigned long timeoutVal = 60; attr_notify_t attrNotify = NOTIFY_UNDEFINED; + char *xsdPath = NULL; + while (1) { int option_index = 0; - c = getopt_long(argc, argv, "a:c:f:t:dhmvuL:o:", long_options, &option_index); + c = getopt_long(argc, argv, "a:c:f:t:dhmvuL:o:X:", long_options, &option_index); if (c == -1) /* have all command-line options have been parsed? */ break; @@ -1225,6 +1234,16 @@ static int imm_operation(int argc, char adminOwnerName = (SaImmAdminOwnerNameT)malloc(strlen(optarg) + 1); strcpy(adminOwnerName, optarg); break; + case 'X': + if(xsdPath) { + fprintf(stderr, "XSD path is already set\n"); + if(transaction_mode) + return -1; + else + exit(EXIT_FAILURE); + } + xsdPath = strdup(optarg); + break; default: fprintf(stderr, "Try '%s --help' for more information\n", argv[0]); if(transaction_mode) @@ -1270,7 +1289,7 @@ static int imm_operation(int argc, char if (op == LOAD_IMMFILE) { VERBOSE_INFO("importImmXML(xmlFilename=%s, verbose=%d)\n", xmlFilename, verbose); rc = importImmXML(xmlFilename, adminOwnerName, verbose, ccb_safe, - &immHandle, &ownerHandle, &ccbHandle, transaction_mode); + &immHandle, &ownerHandle, &ccbHandle, transaction_mode, xsdPath); if(transaction_mode) { if(rc) { fprintf(stderr, "CCB is aborted\n"); @@ -1478,6 +1497,10 @@ static int imm_operation(int argc, char } } } + if(xsdPath) { + free(xsdPath); + xsdPath = NULL; + } return 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,6 +30,8 @@ #include <assert.h> #include <syslog.h> #include <configmake.h> +#include <sys/stat.h> +#include <errno.h> #include <saAis.h> #include <saImmOm.h> @@ -59,7 +63,8 @@ static char base64_dec_table[] = { extern "C" { int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, - SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle, SaImmCcbHandleT *ccbHandle, int mode); + SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle, + SaImmCcbHandleT *ccbHandle, int mode, const char *xsdPath); int validateImmXML(const char *xmlfile, int verbose, int mode); } @@ -143,6 +148,10 @@ typedef struct ParserStateStruct { int parsingStatus; /* 0 = ok */ } ParserState; +bool isXsdLoaded = false; +static const char *imm_xsd_file; +typedef std::set<std::string> AttrFlagSet; +AttrFlagSet attrFlagSet; /* Prototypes */ @@ -1228,6 +1237,144 @@ 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") && + strcmp(value, "SA_NO_DUPLICATES") && strcmp(value, "SA_NO_DANGLING")) { + 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 */ @@ -1360,6 +1507,13 @@ 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); + stopParser(state); + state->parsingStatus = 1; + } + } } else { LOG_ER("UNKNOWN TAG! (%s)", name); stopParser(state); @@ -1776,11 +1930,11 @@ static void charactersHandler(void* user case FLAG: { SaImmAttrFlagsT flg = charsToFlagsHelper(chars, (size_t)len); - if(flg) - state->attrFlags |= flg; - else { + if(flg == 0xffffffffffffffff) { stopParser(state); state->parsingStatus = 1; + } else { + state->attrFlags |= flg; } } break; @@ -1839,18 +1993,17 @@ static SaImmAttrFlagsT charsToFlagsHelpe return SA_IMM_ATTR_NO_DANGLING; } - /* strlen("SA_NO_DUPLICATES") == 16 (the longest flag name) - * A bit longer string is taken to log, max 20 characters. - */ - char unknown[21]; - if(len > 20) - len = 20; - memcpy(unknown, str, len); - unknown[len] = 0; - - LOG_ER("UNKNOWN FLAGS, %s", unknown); - - return 0; + std::string flag((char *)str, len); + if(isXsdLoaded) { + AttrFlagSet::iterator it = attrFlagSet.find(flag); + if(it != attrFlagSet.end()) { + return 0; + } + } + + LOG_ER("UNKNOWN FLAGS, %s", flag.c_str()); + + return 0xffffffffffffffff; } /** @@ -2506,7 +2659,8 @@ int loadImmXML(const char *xmlfile) // 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, - SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle, SaImmCcbHandleT *ccbHandle, int mode) + SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle, + SaImmCcbHandleT *ccbHandle, int mode, const char *xsdPath) { imm_import_adminOwnerName = adminOwnerName; imm_import_verbose = verbose; @@ -2517,6 +2671,9 @@ int importImmXML(char* xmlfileC, char* a imm_import_ccbHandle = ccbHandle; transaction_mode = mode; + imm_xsd_file = xsdPath; + isXsdLoaded = false; + attrFlagSet.clear(); LOG_IN("file: %s adminOwner: %s", xmlfileC, adminOwnerName); ------------------------------------------------------------------------------ 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