Hi Dejan,

On Wed, 2011-03-09 at 14:00 +0100, Dejan Muhamedagic wrote:
> Hi Holger,

> > > > 
> > > > This would become:
> > > > 
> > > >            for p in all_obj_list: # passed from _verify()
> > > >                            if is_primitive(p.node):
> > > > 
> > > > > +            process_primitive(p.node, clash_dict)
> > > > 
> > > > Or perhaps to loop through self.obj_list and build clash_dict
> > > > against all elements? Otherwise, you'll need to skip elements
> > > > which don't pass the check but are not new/changed (in
> > > > self.obj_list).
> > > > 
> > > 
> > 
> > I did not pass "set_obj_verify" in semantic check as this variable "only
> > by chance" contains the right values.
> 
> But it's not by chance. As I wrote earlier, it always contains
> the whole CIB. It has to, otherwise crm_verify wouldn't work. It
> should actually be renamed to set_obj_all or similar. Since we
> already have that list created, it's better to reuse it than to
> create another one from scratch. Further, we may need to add more
> semantic checks which would require looking at the whole CIB.
> 

OK, I implemented it this way.

In order to show the intention of the arguments clearer:

Instead of

    def _verify(self, set_obj_semantic, set_obj_all = None):
        if not set_obj_all:
            set_obj_all = set_obj_semantic
        rc1 = set_obj_all.verify()
        if user_prefs.check_frequency != "never":
            rc2 = set_obj_semantic.semantic_check(set_obj_all)
        else:
            rc2 = 0
        return rc1 and rc2 <= 1
    def verify(self,cmd):
        "usage: verify"
        if not cib_factory.is_cib_sane():
            return False
        return self._verify(mkset_obj("xml"))

This way (always passing both args):

    def _verify(self, set_obj_semantic, set_obj_all):
        rc1 = set_obj_all.verify()
        if user_prefs.check_frequency != "never":
            rc2 = set_obj_semantic.semantic_check(set_obj_all)
        else:
            rc2 = 0
        return rc1 and rc2 <= 1
    def verify(self,cmd):
        "usage: verify"
        if not cib_factory.is_cib_sane():
            return False
        set_obj_all = mkset_obj("xml")
        return self._verify(set_obj_all, set_obj_all)


> My only remaining concern is performance. Though the meta-data is
> cached, perhaps it will pay off to save the RAInfo instance with
> the element. But we can worry about that later.
> 

I can work on this as next step.

> Cheers,
> 
> Dejan
> 

- holger

diff -r a35d8d6d0ab1 shell/modules/cibconfig.py
--- a/shell/modules/cibconfig.py	Wed Mar 09 11:21:03 2011 +0100
+++ b/shell/modules/cibconfig.py	Wed Mar 09 19:53:50 2011 +0100
@@ -230,11 +230,68 @@
         See below for specific implementations.
         '''
         pass
-    def semantic_check(self):
+
+    def __check_unique_clash(self, set_obj_all):
+        'Check whether resource parameters with attribute "unique" clash'
+
+        def process_primitive(prim, clash_dict):
+            '''
+            Update dict clash_dict with
+            (ra_class, ra_provider, ra_type, name, value) -> [ resourcename ]
+            if parameter "name" should be unique
+            '''
+            ra_class = prim.getAttribute("class")
+            ra_provider = prim.getAttribute("provider")
+            ra_type = prim.getAttribute("type")
+            ra_id = prim.getAttribute("id")
+
+            ra = RAInfo(ra_class, ra_type, ra_provider)
+            if ra == None:
+                return
+            ra_params = ra.params()
+
+            attributes = prim.getElementsByTagName("instance_attributes")
+            if len(attributes) == 0:
+                return
+
+            for p in attributes[0].getElementsByTagName("nvpair"):
+                name = p.getAttribute("name")
+                if ra_params[ name ]['unique'] == '1':
+                    value = p.getAttribute("value")
+                    k = (ra_class, ra_provider, ra_type, name, value)
+                    try:
+                        clash_dict[k].append(ra_id)
+                    except:
+                        clash_dict[k] = [ra_id]
+            return
+
+        # we check the whole CIB for clashes as a clash may originate between
+        # an object already committed and a new one
+        clash_dict = {}
+        for obj in set_obj_all.obj_list:
+            node = obj.node
+            if is_primitive(node):
+                process_primitive(node, clash_dict)
+
+        # but we only warn if a 'new' object is involved 
+        check_set = set([o.node.getAttribute("id") for o in self.obj_list if is_primitive(o.node)])
+
+        rc = 0
+        for param, resources in clash_dict.items():
+            # at least one new object must be involved
+            if len(resources) > 1 and len(set(resources) & check_set) > 0:
+                    rc = 2
+                    msg = 'Resources %s violate uniqueness for parameter "%s": "%s"' %\
+                            (",".join(sorted(resources)), param[3], param[4])
+                    common_warning(msg)
+
+        return rc
+
+    def semantic_check(self, set_obj_all):
         '''
         Test objects for sanity. This is about semantics.
         '''
-        rc = 0
+        rc = self.__check_unique_clash(set_obj_all)
         for obj in self.obj_list:
             rc |= obj.check_sanity()
         return rc
diff -r a35d8d6d0ab1 shell/modules/ui.py.in
--- a/shell/modules/ui.py.in	Wed Mar 09 11:21:03 2011 +0100
+++ b/shell/modules/ui.py.in	Wed Mar 09 19:53:50 2011 +0100
@@ -1425,12 +1425,12 @@
         set_obj = mkset_obj(*args)
         err_buf.release() # show them, but get an ack from the user
         return set_obj.edit()
-    def _verify(self, set_obj_semantic, set_obj_verify = None):
-        if not set_obj_verify:
-            set_obj_verify = set_obj_semantic
-        rc1 = set_obj_verify.verify()
+    def _verify(self, set_obj_semantic, set_obj_all = None):
+        if not set_obj_all:
+            set_obj_all = set_obj_semantic
+        rc1 = set_obj_all.verify()
         if user_prefs.check_frequency != "never":
-            rc2 = set_obj_semantic.semantic_check()
+            rc2 = set_obj_semantic.semantic_check(set_obj_all)
         else:
             rc2 = 0
         return rc1 and rc2 <= 1
_______________________________________________
Pacemaker mailing list: Pacemaker@oss.clusterlabs.org
http://oss.clusterlabs.org/mailman/listinfo/pacemaker

Project Home: http://www.clusterlabs.org
Getting started: http://www.clusterlabs.org/doc/Cluster_from_Scratch.pdf
Bugs: http://developerbugs.linux-foundation.org/enter_bug.cgi?product=Pacemaker

Reply via email to