Hi,

Any comment from you? I will push this ticket B/next week if no comment.

Regards, Vu

> -----Original Message-----
> From: Vu Minh Nguyen <vu.m.ngu...@dektech.com.au>
> Sent: Wednesday, December 19, 2018 6:11 PM
> To: hans.nordeb...@ericsson.com; lennart.l...@ericsson.com;
> gary....@dektech.com.au
> Cc: opensaf-devel@lists.sourceforge.net; Vu Minh Nguyen
> <vu.m.ngu...@dektech.com.au>
> Subject: [PATCH 1/1] imm: allow empty-value attribute with default-tag
> persisted [#2985]
> 
> During runtime, when replacing value of an attribute which has
default-value
> tag with NULL, this NULL value is not persistent after cluster is rebooted
-
> NULL value will be automatically replaced with its default value by IMM.
> 
> This behavior causes several unexpected results. Below is a use case.
> 
> User defines an attribute with name `maxAge`. It is used to shows how many
> days
> user passwords will be expired, default value is 30 days; if replacing
with
> a NULL/empty, it means the passwords will never get expired.
> 
> During runtime, user changes the existing value with NULL - expect the
> passwords
> never get expired. Later on, then cluster is rebooted, that value is
silently
> replaced with the default without notice of user.
> 
> This patch makes some changes in immdump/immloader/imm om
> library/immnd
> to make NULL value in such case persisted even after cluster is rebooted.
> ---
>  src/imm/README                   | 10 +---
>  src/imm/agent/imma_om_api.cc     |  7 ++-
>  src/imm/immloadd/imm_loader.cc   | 23 +++++---
>  src/imm/immloadd/imm_pbe_load.cc | 16 ++++--
>  src/imm/immnd/ImmModel.cc        |  9 ++-
>  src/imm/tools/imm_xmlw_dump.cc   | 96 ++++++++++++++++++++------------
>  6 files changed, 100 insertions(+), 61 deletions(-)
> 
> diff --git a/src/imm/README b/src/imm/README
> index 7ace34741..132ee0ac0 100644
> --- a/src/imm/README
> +++ b/src/imm/README
> @@ -351,14 +351,8 @@ as part of an attribute definition.
>  (i) A default declaration is only allowed for single valued attributes
(no
>  concept of a multivalued default exists).
> 
> -(ii) Default values are assigned at object creation. Default values are
NOT
> -assigned if an attribute is set to the empty/null value by a
modification.
> -
> -(iii) Default values are assigned at cluster restart for any attributes
that
> -are null/empty and that have a default. This is a special case of (i)
because
> -imm loading actually uses the regular imm API to recreate the imm
contents.
> -In particular, saImmOmCcbObjectCreate is used to recreate all objects
from
> -the file-system image.
> +(ii) Default values are assigned at object creation, except the creation
> comes
> +from IMM loader.
> 
>  Common missunderstandings about "system attributes" of an imm object.
>  ---------------------------------------------------------------------
> diff --git a/src/imm/agent/imma_om_api.cc
> b/src/imm/agent/imma_om_api.cc
> index 7155799d9..0d24b2335 100644
> --- a/src/imm/agent/imma_om_api.cc
> +++ b/src/imm/agent/imma_om_api.cc
> @@ -2037,7 +2037,7 @@ static SaAisErrorT ccb_object_create_common(
>          TRACE_2("ERR_INVALID_PARAM: Not allowed to set attribute %s",
>                  sysaImplName);
>          goto mds_send_fail;
> -      } else if (attr->attrValuesNumber == 0) {
> +      } else if (attr->attrValuesNumber == 0 && !immOmIsLoader) {
>          TRACE("CcbObjectCreate ignoring attribute %s with no values",
>                attr->attrName);
>          continue;
> @@ -2065,7 +2065,9 @@ static SaAisErrorT ccb_object_create_common(
> 
>        const SaImmAttrValueT *avarr = attr->attrValues;
>        /*alloc-5 */
> -      imma_copyAttrValue(&(p->n.attrValue), attr->attrValueType,
avarr[0]);
> +      if (attr->attrValuesNumber > 0) {
> +        imma_copyAttrValue(&(p->n.attrValue), attr->attrValueType,
avarr[0]);
> +      }
> 
>        if (attr->attrValuesNumber > 1) {
>          unsigned int numAdded = attr->attrValuesNumber - 1;
> @@ -2087,6 +2089,7 @@ static SaAisErrorT ccb_object_create_common(
>      }
>    }
> 
> +
>    rc = imma_evt_fake_evs(cb, &evt, &out_evt, cl_node->syncr_timeout,
>                           cl_node->handle, &locked, false);
>    cl_node = NULL;
> diff --git a/src/imm/immloadd/imm_loader.cc
> b/src/imm/immloadd/imm_loader.cc
> index e9a985c22..3bd3e2b2e 100644
> --- a/src/imm/immloadd/imm_loader.cc
> +++ b/src/imm/immloadd/imm_loader.cc
> @@ -117,6 +117,7 @@ typedef struct ParserStateStruct {
>    SaImmAttrFlagsT attrFlags;
>    SaUint32T attrNtfId;
>    char *attrDefaultValueBuffer;
> +  bool is_null_value;
> 
>    int attrValueTypeSet;
>    int attrNtfIdSet;
> @@ -925,6 +926,13 @@ static void startElementHandler(void *userData,
> const xmlChar *name,
>      state->state[state->depth] = VALUE;
>      state->valueContinue = 0;
>      state->isBase64Encoded = isBase64Encoded(attrs);
> +    state->is_null_value = false;
> +    if (attrs) {
> +      char* null_value = getAttributeValue("xsi:nil", attrs);
> +      if (null_value && std::string{null_value} == "true") {
> +        state->is_null_value = true;
> +      }
> +    }
>      /* <category> */
>    } else if (strcmp((const char *)name, "category") == 0) {
>      state->state[state->depth] = CATEGORY;
> @@ -982,7 +990,7 @@ static void endElementHandler(void *userData, const
> xmlChar *name) {
> 
>    /* </value> */
>    if (strcmp((const char *)name, "value") == 0) {
> -    if (state->attrValueBuffers.empty()) {
> +    if (state->attrValueBuffers.empty() && !state->is_null_value) {
>        char *str = (char *)malloc(1);
> 
>        str[0] = '\0';
> @@ -1759,14 +1767,13 @@ void addObjectAttributeDefinition(
>    SaImmAttrValuesT_2 attrValues;
>    int i;
>    size_t len;
> +  bool null_value = attrValueBuffers->empty();
> +
>    TRACE_ENTER2("attrValueBuffers size:%u",
>                 (unsigned int)attrValueBuffers->size());
>    /* The attrName must be set */
>    assert(attrName);
> 
> -  /* The value array can not be empty */
> -  assert(!attrValueBuffers->empty());
> -
>    /* The object class must be set */
>    assert(objectClass);
> 
> @@ -1778,15 +1785,15 @@ void addObjectAttributeDefinition(
> 
>    /* For each value, convert from char* to SaImmAttrValuesT_2 and
>       store an array pointing to all in attrValues */
> -  attrValues.attrValuesNumber = attrValueBuffers->size();
> -  attrValues.attrValues = (SaImmAttrValueT *)malloc(
> +  attrValues.attrValuesNumber = null_value ? 0 :
attrValueBuffers->size();
> +  attrValues.attrValues = null_value ? nullptr : (SaImmAttrValueT
*)malloc(
>        sizeof(SaImmAttrValuesT_2) * attrValues.attrValuesNumber + 1);
> 
> -  attrValues.attrValues[attrValues.attrValuesNumber] = NULL;
> +  if (!null_value) attrValues.attrValues[attrValues.attrValuesNumber] =
> NULL;
> 
>    it = attrValueBuffers->begin();
>    i = 0;
> -  while (it != attrValueBuffers->end()) {
> +  while (!null_value && it != attrValueBuffers->end()) {
>      charsToValueHelper(&attrValues.attrValues[i],
attrValues.attrValueType,
>                         *it);
>      i++;
> diff --git a/src/imm/immloadd/imm_pbe_load.cc
> b/src/imm/immloadd/imm_pbe_load.cc
> index d9e1c4d83..72b926383 100644
> --- a/src/imm/immloadd/imm_pbe_load.cc
> +++ b/src/imm/immloadd/imm_pbe_load.cc
> @@ -524,7 +524,8 @@ bool loadObjectFromPbe(void *pbeHandle,
> SaImmHandleT immHandle,
>    const unsigned char *res;
>    for (c = 0; c < ncols; ++c) {
>      res = sqlite3_column_text(stmt, c);
> -    if (res) {
> +    bool is_null = false;
> +    if (true) {
>        SaImmValueTypeT attrType = (SaImmValueTypeT)0;
>        const char *colname = sqlite3_column_name(stmt, c);
>        assert(colname != NULL);
> @@ -544,7 +545,7 @@ bool loadObjectFromPbe(void *pbeHandle,
> SaImmHandleT immHandle,
>        assert(it != class_info->attrInfoVector.end());
> 
>        char *val;
> -      if (attrType == SA_IMM_ATTR_SADOUBLET) {
> +      if (res && attrType == SA_IMM_ATTR_SADOUBLET) {
>          double dbl = sqlite3_column_double(stmt, c);
> 
>          val = (char *)malloc(30);
> @@ -555,12 +556,16 @@ bool loadObjectFromPbe(void *pbeHandle,
> SaImmHandleT immHandle,
>            snprintf(val, size, "%.17g", dbl);
>          }
>        } else {
> -        val = strdup((const char *)res);
> +        if (res) {
> +          val = strdup((const char *)res);
> +        }
>        }
> 
> +      is_null = (res == nullptr);
>        std::list<char *> attrValueBuffers;
> -      attrValueBuffers.push_front(val);
> -
> +      if (!is_null) {
> +        attrValueBuffers.push_front(val);
> +      }
>        addObjectAttributeDefinition((char *)class_info->className.c_str(),
>                                     (SaImmAttrNameT)colname,
&attrValueBuffers,
>                                     attrType, &attrValuesList);
> @@ -669,7 +674,6 @@ bool loadObjectFromPbe(void *pbeHandle,
> SaImmHandleT immHandle,
>                                       (char *)(*it)->attrName.c_str(),
>                                       &attrValueBuffers,
(*it)->attrValueType,
>                                       &attrValuesList);
> -
>        sqlite3_reset(stmt);
>      } /*if(attr_is_multi && !attr_is_pure_rt)*/
>      ++it;
> diff --git a/src/imm/immnd/ImmModel.cc b/src/imm/immnd/ImmModel.cc
> index 8e3f338dc..747b406c6 100644
> --- a/src/imm/immnd/ImmModel.cc
> +++ b/src/imm/immnd/ImmModel.cc
> @@ -8393,8 +8393,13 @@ SaAisErrorT ImmModel::ccbObjectCreate(
> 
>        ImmAttrValue* attrValue = i6->second;
>        IMMSV_OCTET_STRING tmpos;  // temporary octet string
> -      eduAtValToOs(&tmpos, &(p->n.attrValue),
> -                   (SaImmValueTypeT)p->n.attrValueType);
> +      memset(&tmpos, 0, sizeof(tmpos));
> +      // Attribute value will be assigned null value or <empty>
> +      // if having `attrValuesNumber=0` goes with it.
> +      if (p->n.attrValuesNumber) {
> +        eduAtValToOs(&tmpos, &(p->n.attrValue),
> +                     (SaImmValueTypeT)p->n.attrValueType);
> +      }
>        attrValue->setValue(tmpos);
>        if (p->n.attrValuesNumber > 1) {
>          /*
> diff --git a/src/imm/tools/imm_xmlw_dump.cc
> b/src/imm/tools/imm_xmlw_dump.cc
> index 2e7fcda86..e6fdd279f 100644
> --- a/src/imm/tools/imm_xmlw_dump.cc
> +++ b/src/imm/tools/imm_xmlw_dump.cc
> @@ -419,11 +419,6 @@ void objectToXMLw(std::string objectNameString,
> SaImmAttrValuesT_2** attrs,
>      exit(1);
>    }
>    for (SaImmAttrValuesT_2** p = attrs; *p != NULL; p++) {
> -    /* Skip attributes with attrValues = NULL */
> -    if ((*p)->attrValues == NULL) {
> -      continue;
> -    }
> -
>      if (classRDNMap.find(classNameString) != classRDNMap.end() &&
>          classRDNMap[classNameString] == std::string((*p)->attrName)) {
>        continue;
> @@ -469,10 +464,6 @@ static void StoreObject(const std::string&
> objectName,
> 
>    /* Add attributes to list */
>    for (SaImmAttrValuesT_2** p = attrs; *p != NULL; p++) {
> -    /* Skip attributes with attrValues = NULL */
> -    if ((*p)->attrValues == NULL) {
> -      continue;
> -    }
>      /* Skip RDN */
>      if (classRDNMap.find(obj.className) != classRDNMap.end() &&
>          classRDNMap[obj.className] == std::string((*p)->attrName)) {
> @@ -544,42 +535,62 @@ static void ObjectSetToXMLw(std::set<Object,
> ObjectComp>& objectSet,
>        }
> 
>        /* Write attribute values */
> -      for (std::list<std::string>::const_iterator value_it =
> -               attr_it->second.begin();
> -           value_it != attr_it->second.end(); ++value_it) {
> +      std::list<std::string> values = attr_it->second;
> +      if (values.empty()) {
>          if (xmlTextWriterStartElement(writer, (xmlChar*)"value") < 0) {
>            std::cout << "Error at xmlTextWriterStartElement (value)"
>                      << std::endl;
>            exit(1);
>          }
> -        if (osaf_is_valid_xml_utf8((*value_it).c_str())) {
> -          if (xmlTextWriterWriteString(writer,
(xmlChar*)(*value_it).c_str()) <
> -              0) {
> -            std::cout << "Error at xmlTextWriterWriteString (value)"
> -                      << std::endl;
> -            exit(1);
> -          }
> -        } else {
> -          if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:type",
> -                                          (xmlChar*)"xs:base64Binary") <
0) {
> -            std::cout << "Error at xmlTextWriterWriteAttribute (value)"
> -                      << std::endl;
> -            exit(1);
> -          }
> -          if (xmlTextWriterWriteBase64(writer, (*value_it).c_str(), 0,
> -                                       (*value_it).size()) < 0) {
> -            std::cout << "Error at xmlTextWriterWriteBase64 (value)"
> -                      << std::endl;
> -            exit(1);
> -          }
> +        if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:nil",
> +                                        (xmlChar*)"true") < 0) {
> +          std::cout << "Error at xmlTextWriterWriteAttribute (value)"
> +                    << std::endl;
> +          exit(1);
>          }
>          if (xmlTextWriterEndElement(writer) < 0) {
>            std::cout << "Error at xmlTextWriterWriteEndElement (value)"
>                      << std::endl;
>            exit(1);
>          }
> -      } /* Attribute values loop */
> 
> +      } else {
> +        for (std::list<std::string>::const_iterator value_it =
> +                 attr_it->second.begin();
> +             value_it != attr_it->second.end(); ++value_it) {
> +          if (xmlTextWriterStartElement(writer, (xmlChar*)"value") < 0) {
> +            std::cout << "Error at xmlTextWriterStartElement (value)"
> +                      << std::endl;
> +            exit(1);
> +          }
> +          if (osaf_is_valid_xml_utf8((*value_it).c_str())) {
> +            if (xmlTextWriterWriteString(writer,
(xmlChar*)(*value_it).c_str()) <
> +                0) {
> +              std::cout << "Error at xmlTextWriterWriteString (value)"
> +                        << std::endl;
> +              exit(1);
> +            }
> +          } else {
> +            if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:type",
> +                                            (xmlChar*)"xs:base64Binary")
< 0) {
> +              std::cout << "Error at xmlTextWriterWriteAttribute (value)"
> +                        << std::endl;
> +              exit(1);
> +            }
> +            if (xmlTextWriterWriteBase64(writer, (*value_it).c_str(), 0,
> +                                         (*value_it).size()) < 0) {
> +              std::cout << "Error at xmlTextWriterWriteBase64 (value)"
> +                        << std::endl;
> +              exit(1);
> +            }
> +          }
> +          if (xmlTextWriterEndElement(writer) < 0) {
> +            std::cout << "Error at xmlTextWriterWriteEndElement (value)"
> +                      << std::endl;
> +            exit(1);
> +          }
> +        } /* Attribute values loop */
> +      }
>        if (xmlTextWriterEndElement(writer) < 0) {
>          std::cout << "Error at xmlTextWriterEndElement (attr-object)"
>                    << std::endl;
> @@ -597,8 +608,23 @@ static void ObjectSetToXMLw(std::set<Object,
> ObjectComp>& objectSet,
>  }
> 
>  void valuesToXMLw(SaImmAttrValuesT_2* p, xmlTextWriterPtr writer) {
> -  if (!p->attrValues) {
> -    // std::cout << "No values!" << std::endl;
> +  if (p->attrValuesNumber == 0) {
> +    if (xmlTextWriterStartElement(writer, (xmlChar*)"value") < 0) {
> +      std::cout << "Error at xmlTextWriterStartElement (value)"
> +                << std::endl;
> +      exit(1);
> +    }
> +    if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:nil",
> +                                    (xmlChar*)"true") < 0) {
> +      std::cout << "Error at xmlTextWriterWriteAttribute (value)"
> +                << std::endl;
> +      exit(1);
> +    }
> +    if (xmlTextWriterEndElement(writer) < 0) {
> +      std::cout << "Error at xmlTextWriterWriteEndElement (value)"
> +                << std::endl;
> +      exit(1);
> +    }
>      return;
>    }
> 
> --
> 2.19.2




_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to