Hi Hung,

This was caused by the two mistakes below. I will include these in the 
updated changeset.

/ Johan

opensaf-staging$ hg diff
diff --git a/python/pyosaf/utils/immoi/__init__.py 
b/python/pyosaf/utils/immoi/__init__.py
--- a/python/pyosaf/utils/immoi/__init__.py
+++ b/python/pyosaf/utils/immoi/__init__.py
@@ -378,7 +378,11 @@ def create_non_existing_imm_object(class
      rdn_attribute = get_rdn_attribute_for_class(class_name)
      rdn_value     = attributes[rdn_attribute][0]

-    dn  = '%s,%s' % (rdn_value, parent_name)
+    if parent_name:
+        dn  = '%s,%s' % (rdn_value, parent_name)
+    else:
+        dn = rdn_value
+
      obj = ImmObject(class_name = class_name, dn=dn)

      for name, values in attributes.iteritems():
diff --git a/python/pyosaf/utils/immoi/implementer.py 
b/python/pyosaf/utils/immoi/implementer.py
--- a/python/pyosaf/utils/immoi/implementer.py
+++ b/python/pyosaf/utils/immoi/implementer.py
@@ -548,7 +548,13 @@ class Constraints:
              if parent_name in deleted:
                  continue

-            parent_class = immoi.get_class_name_for_dn(parent_name)
+            # Avoid looking up the parent class in IMM if possible
+            parent_mos = filter(lambda x: x.dn == parent_name, 
all_instances)
+
+            if parent_mos:
+                parent_class = parent_mos[0].class_name
+            else:
+                parent_class = immoi.get_class_name_for_dn(parent_name)

              # Ignore children where no constraint is defined for the 
child or the parent
              if not parent_class in self.containments and not \
@@ -569,7 +575,6 @@ class Constraints:
              current_children = get_children_with_classname(parent_name,
all_instances,
mo.class_name)
-
              # Validate the number of children of the specific class to 
the given parent
              lower, upper = self.cardinality[(parent_class, mo.class_name)]



On 09/15/2015 09:28 AM, Hung Nguyen wrote:
> Hi Johan,
>
> I failed to create the objects in the same CCB.
>
> root@SC1:~# immcfg
> > immcfg -c Do doId=1
> > immcfg -c Re reId=1,doId=1
> > immcfg -c Mi miId=1,reId=1,doId=1
> > immcfg --ccb-apply
> error - saImmOmCcbApply FAILED: SA_AIS_ERR_FAILED_OPERATION (21)
> CCB is aborted
>
> Please see inline comments for details.
>
> Best Regards,
> Hùng Nguyễn - DEK Technologies
>
>
>
> ------------------------------------------------------------------------
>
> *From:* Johan Martensson
> *Sent:* Monday, September 14, 2015 9:31PM
> *To:* Hans Nordeback, Mathivanan Naickan, Hung Nguyen, Srikanth 
> Revanuru (srikanth.revan...@oracle.com)
> *Cc:* Opensaf-devel
> *Subject:* [PATCH 13 of 15] pyosaf: Correct cardinality validation and 
> validate 'deleted' argument [#1406]
>
>   python/pyosaf/utils/immoi/__init__.py    |    6 +-
>   python/pyosaf/utils/immoi/implementer.py |  149 
> ++++++++++++++++--------------
>   2 files changed, 84 insertions(+), 71 deletions(-)
>
>
> Correct the cardinality validation and the 'deleted' argument to the validate 
> callback according to review comments. The deleted MOs were passed as 
> ImmObjects but this doesn't work for the applier case so now they are passed 
> as DNs instead.
>
> diff --git a/python/pyosaf/utils/immoi/__init__.py 
> b/python/pyosaf/utils/immoi/__init__.py
> --- a/python/pyosaf/utils/immoi/__init__.py
> +++ b/python/pyosaf/utils/immoi/__init__.py
> @@ -235,7 +235,11 @@ def get_class_category(class_name):
>   
>   def get_parent_name_for_dn(dn):
>       ''' returns the dn of the parent of the instance of the given dn '''
> -    return ",".join(dn.split(',')[1:])
> +
> +    if ',' in dn:
> +        return dn.split(',', 1)[1]
> +    else:
> +        return None
>   
>   def get_object_names_for_class(class_name, root_name=None):
>       ''' Returns the instances of the given class, optinally under the given 
> root dn
> diff --git a/python/pyosaf/utils/immoi/implementer.py 
> b/python/pyosaf/utils/immoi/implementer.py
> --- a/python/pyosaf/utils/immoi/implementer.py
> +++ b/python/pyosaf/utils/immoi/implementer.py
> @@ -61,7 +61,7 @@ def _collect_full_transaction(ccb_id):
>       for class_name in implementer_instance.class_names:
>           dns = immoi.get_object_names_for_class(class_name)
>           for dn in dns:
> -            obj = immoi.get_object_no_runtime(dn, class_name)
> +            obj = immoi.get_object_no_runtime(dn)
>   
>               all_objects_now.append(obj)
>   
> @@ -88,15 +88,14 @@ def _collect_full_transaction(ccb_id):
>   
>               created.append(instance)
>   
> -            deleted = filter(lambda i: i.dn != dn, deleted)
> +            if dn in deleted:
> +                deleted.remove(dn)
>   
>           # Handle deletes
>           elif operation_type == 'DELETE':
>               dn = operation['dn']
>   
> -            obj = immom.get(dn)
> -
> -            deleted.append(obj)
> +            deleted.append(dn)
>   
>               created = filter(lambda i: i.dn != dn, created)
>               updated = filter(lambda i: i.dn != dn, updated)
> @@ -149,13 +148,8 @@ def _collect_full_transaction(ccb_id):
>       instances_after = []
>   
>       for mo in itertools.chain(all_objects_now, created):
> -        is_deleted = False
>   
> -        for deleted_mo in deleted:
> -            if deleted_mo.dn == mo.dn:
> -                is_deleted = True
> -
> -        if not deleted:
> +        if not mo.dn in deleted:
>               instances_after.append(mo)
>   
>       out = {'instances_after' : instances_after,
> @@ -213,7 +207,7 @@ def apply_ccb(oi_handle, ccb_id):
>           dns = immoi.get_object_names_for_class(class_name)
>   
>           for dn in dns:
> -            obj = immoi.get_object_no_runtime(dn, class_name)
> +            obj = immoi.get_object_no_runtime(dn)
>   
>               all_instances.append(obj)
>   
> @@ -499,77 +493,95 @@ class Constraints:
>   
>           self.cardinality[pair] = [lower, upper]
>   
> +
>       def validate(self, all_instances, updated, created, deleted):
>           ''' Validates the constraints in this Constraints instance '''
>   
> -        # Validate containments
> -        for mo in created:
> +        def get_children_with_classname(parent_name, all_instances, 
> class_name):
> +            ''' Helper method to count the number of children of the given 
> class
> +                in the list of all instances '''
> +            current_children = []
> +
> +            for child in all_instances:
> +
> +                if not ',' in child.dn:
> +                    continue
> +
> +                if immoi.get_parent_name_for_dn(child.dn) == parent_name and 
> \
> +                   child.class_name == class_name:
> +                    current_children.append(child)
> +
> +            return current_children
> +
> +        def constraint_exists_for_child(class_name):
> +            ''' Returns true if there exists a constraint for the given 
> class as
> +                a child
> +            '''
> +            for child_classes in self.containments.values():
> +                if class_name in child_classes:
> +                    return True
> +
> +            return False
> +
> +        # Validate containments affected by create or delete
> +        deleted_mos = [immoi.get_object_no_runtime(deleted_mo) \
> +                       for deleted_mo in deleted]
> +
> +        for mo in itertools.chain(created, deleted_mos):
>   
>               parent_name = immoi.get_parent_name_for_dn(mo.dn)
>   
>               # Handle the case where there is no parent
>               if not parent_name:
>   
> -                for parent_class, child_classes in 
> self.containments.iteritems():
> -                    if mo.SaImmAttrClassName in child_classes:
> -                        error_string = "ERROR: Cannot create %s, %s must 
> have a parent" % \
> -                                       (mo.dn, mo.SaImmAttrClassName)
> -                        raise 
> SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM,
> -                                           error_string)
> -
> -            else:
> -
> -                parent_class = immoi.get_class_name_for_dn(parent_name)
> -
> -                child_classes = self.containments[parent_class]
> -
> -                if not mo.SaImmAttrClassName in child_classes:
> -                    error_string = "ERROR: Cannot create %s as a child under 
> %s. Possible children are %s" % \
> -                                   (mo.dn, parent_class, child_classes)
> -                    raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM,
> +                if mo in created and \
> +                   constraint_exists_for_child(mo.class_name):
> +                    error_string = "ERROR: Cannot create %s, %s must have a 
> parent" % \
> +                                   (mo.dn, mo.SaImmAttrClassName)
> +                    raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM,
>                                          error_string)
>   
> -        # Validate cardinality of containments
> -        count_cardinality = {}
> -
> -        for mo in all_instances:
> -
> -            parent_name = immoi.get_parent_name_for_dn(mo.dn)
> -
> -            if parent_name:
> -
> -                parent_class = immoi.get_class_name_for_dn(parent_name)
> -
> -                # Count children of each parent-child relationship
> -                pair = (parent_class, mo.SaImmAttrClassName)
> -
> -                if not pair in count_cardinality:
> -                    count_cardinality[pair] = 0
> -
> -                count_cardinality[pair] += 1
> -
> -        # Verify the cardinality
> -        for counted_pair, number in count_cardinality.iteritems():
> -            parent_class = counted_pair[0]
> -            child_class  = counted_pair[1]
> -
> -            # Ignore pairs that have no specified cardinality
> -            if not counted_pair in self.cardinality:
> +                # Allow this operation and check the next one
>                   continue
>   
> -            lower = self.cardinality[counted_pair][0]
> -            upper = self.cardinality[counted_pair][1]
> +            # Handle the case where the parent is also deleted
> +            if parent_name in deleted:
> +                continue
>   
> -            if lower and number < lower:
> -                error_string = "ERROR: Must have at least %s instances of %s 
> under %s" % \
> -                               (lower, child_class, parent_class)
> +            parent_class = immoi.get_class_name_for_dn(parent_name)
>
> [Hung] If the parent is being created in the same CCB, saImmOmAccessorGet_2() 
> will return ERR_NOT_EXIST
> and immoi.get_class_name_for_dn() will return None.
>
> I suggest to look up the 'created' list for the class of parent_name when 
> immoi.get_class_name_for_dn() returns None.
>
> +
> +            # Ignore children where no constraint is defined for the child 
> or the parent
> +            if not parent_class in self.containments and not \
> +               constraint_exists_for_child(mo.class_name):
> +                continue
> +
> +            # Validate the containment if there is a parent
> +            child_classes = self.containments[parent_class]
>
> [Hung] parent_class being None causes a KeyError exception here and the CCB 
> will be aborted.
>
> +
> +            # Reject the create if the child's class is not part of the 
> allowed child classes
> +            if not mo.class_name in child_classes and mo in created:
> +                error_string = "ERROR: Cannot create %s as a child under %s. 
> Possible children are %s" % \
> +                               (mo.dn, parent_class, child_classes)
>                   raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM,
>                                      error_string)
> -            elif upper and number > upper:
> +
> +            # Count current containments
> +            current_children = get_children_with_classname(parent_name,
> +                                                           all_instances,
> +                                                           mo.class_name)
> +
> +            # Validate the number of children of the specific class to the 
> given parent
> +            lower, upper = self.cardinality[(parent_class, mo.class_name)]
> +
> +            if lower and len(current_children) < lower:
> +                error_string = "ERROR: Must have at least %s instances of %s 
> under %s" % \
> +                               (lower, mo.class_name, parent_class)
> +                raise SafException(eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION, 
> error_string)
> +
> +            if upper and len(current_children) > upper:
>                   error_string = "ERROR: Must have at most %s instances of %s 
> under %s" % \
> -                               (upper, child_class, parent_class)
> -                raise SafException(eSaAisErrorT.SA_AIS_ERR_INVALID_PARAM,
> -                                   error_string)
> +                               (upper, mo.class_name, parent_class)
> +                raise SafException(eSaAisErrorT.SA_AIS_ERR_FAILED_OPERATION, 
> error_string)
>   
>   
>   class Implementer:
> @@ -847,10 +859,7 @@ class Implementer:
>                                 deleted):
>           ''' Validates configured constraints '''
>           if self.constraints:
> -            return self.constraints.validate(all_instances, updated,
> -                                             created, deleted)
> -        else:
> -            return eSaAisErrorT.SA_AIS_OK
> +            self.constraints.validate(all_instances, updated, created, 
> deleted)
>   
>   
>   class Applier(Implementer):
>

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

Reply via email to