On Thu, Jun 06, 2013 at 05:19:03PM +0200, Dejan Muhamedagic wrote:
> Hi,
> 
> On Thu, Jun 06, 2013 at 03:11:16PM +0300, Vladislav Bogdanov wrote:
> > 06.06.2013 08:43, Vladislav Bogdanov wrote:
> > [...]
> > >>>>> I recall that LDAP has similar problem, which is easily worked around
> > >>>>> with specifying two values, one is original, second is new.
> > >>>>> That way you tell LDAP server:
> > >>>>> Replace value Y in attribute X to value Z. And if value is not Y at 
> > >>>>> the
> > >>>>> moment of modification request, then command fails.
> > >>>>
> > >>>> "cibadmin --patch" works this way
> > >>>
> > >>> Who is baking new CIB in that case, cibadmin or cib?
> > >>
> > >> The patch is applied on the server - so "cib"
> > > 
> > > Then that is safe way to go, assuming that cib daemon serializes
> > > modification requests.
> > > 
> > 
> > It would be great if crmsh use that trick.
> 
> Hope to have something soon. Stay tuned.

The patch for crmsh is attached and you'll need the very latest
pacemaker (because cibadmin needed some fixing). Unfortunately,
I cannot push this yet to the repository, as the current
pacemaker 1.1.10-rc still identifies itself as 1.1.9. I'd
appreciate if you could test it.

Once again:

        Do not use this patch with anything before pacemaker
        commit 7cd53c!

Cheers,

Dejan

> Thanks,
> 
> Dejan
> _______________________________________________
> Linux-HA mailing list
> [email protected]
> http://lists.linux-ha.org/mailman/listinfo/linux-ha
> See also: http://linux-ha.org/ReportingProblems
# HG changeset patch
# User Dejan Muhamedagic <[email protected]>
# Date 1372250948 -7200
#      Wed Jun 26 14:49:08 2013 +0200
# Node ID c60a0e24683631aa4f7ac5903b0bab51cff472e6
# Parent  186677999fcdc42dbaf97aa211c0d3b45870787b
High: cibconfig: use cibadmin patch to update live CIB

diff -r 186677999fcd -r c60a0e246836 modules/cibconfig.py
--- a/modules/cibconfig.py	Wed Jun 26 14:43:52 2013 +0200
+++ b/modules/cibconfig.py	Wed Jun 26 14:49:08 2013 +0200
@@ -1928,7 +1928,6 @@ class CibFactory(Singleton):
         self._init_vars()
         self.regtest = options.regression_tests
         self.last_commit_time = 0
-        self.all_committed = True # has commit produced error
         self._no_constraint_rm_msg = False # internal (just not to produce silly messages)
         self.supported_cib_re = "^pacemaker-1[.][012]$"
     def is_cib_sane(self):
@@ -2052,18 +2051,15 @@ class CibFactory(Singleton):
     # create a doc from the list of objects
     # (used by CibObjectSetRaw)
     #
-    def _regtest_filter(self, cib):
-        for attr in ("epoch", "admin_epoch"):
-            if cib.get(attr):
-                cib.set(attr, "0")
-        for attr in ("cib-last-written",):
-            if cib.get(attr):
-                del cib.attrib[attr]
+    def bump_epoch(self):
+        try:
+            self.cib_attrs["epoch"] = str(int(self.cib_attrs["epoch"])+1)
+        except:
+            common_warn("could not bump epoch, setting it to 1")
+            self.cib_attrs["epoch"] = "1"
     def _set_cib_attributes(self, cib):
         for attr in self.cib_attrs:
             cib.set(attr, self.cib_attrs[attr])
-        if self.regtest:
-            self._regtest_filter(cib)
     def objlist2doc(self, obj_list, obj_filter=None):
         '''
         Return document containing objects in obj_list.
@@ -2096,8 +2092,6 @@ class CibFactory(Singleton):
             cib_attr = None
         return c.get(a) == cib_attr
     def is_current_cib_equal(self, silent=False):
-        if self.overwrite:
-            return True
         cib_elem = read_cib(cibdump2elem)
         if cib_elem is None:
             return False
@@ -2122,9 +2116,10 @@ class CibFactory(Singleton):
         'Commit the configuration to the CIB.'
         if not self.is_cib_sane():
             return False
-        # all_committed is updated in the invoked object methods
-        self.all_committed = True
-        rc = self._commit_doc(force)
+        if cibadmin_can_patch():
+            rc = self._patch_cib(force)
+        else:
+            rc = self._replace_cib(force)
         if rc:
             # reload the cib!
             common_debug("CIB commit successful")
@@ -2132,8 +2127,8 @@ class CibFactory(Singleton):
                 self.last_commit_time = time.time()
             self.reset()
             self.initialize()
-        return self.all_committed
-    def _commit_schema(self):
+        return rc
+    def _update_schema(self):
         '''
         Set the validate-with, if the schema changed.
         '''
@@ -2144,13 +2139,13 @@ class CibFactory(Singleton):
             return False
         self.new_schema = False
         return True
-    def _commit_doc(self, force):
+    def _replace_cib(self, force):
         try:
             conf_el = self.cib_elem.findall("configuration")[0]
         except IndexErr:
             common_error("cannot find the configuration element")
             return False
-        if self.new_schema and not self._commit_schema():
+        if self.new_schema and not self._update_schema():
             return False
         cibadmin_opts = force and "-R --force" or "-R"
         rc = pipe_string("%s %s" % (cib_piped, cibadmin_opts), etree.tostring(conf_el))
@@ -2158,6 +2153,22 @@ class CibFactory(Singleton):
             update_err("cib", cibadmin_opts, etree.tostring(conf_el), rc)
             return False
         return True
+    def _patch_cib(self, force):
+        self.bump_epoch()
+        self._set_cib_attributes(self.cib_elem)
+        cibadmin_opts = force and "-P --force" or "-P"
+        # produce a diff:
+        # dump_new_conf | crm_diff -o self.cib_orig -n -
+        rc, cib_diff = filter_string("crm_diff -o %s -n -" % \
+            self.cib_orig, etree.tostring(self.cib_elem))
+        if not cib_diff:
+            common_err("crm_diff apparently failed to produce the diff (rc=%d)" % rc)
+            return False
+        rc = pipe_string("%s %s" % (cib_piped,cibadmin_opts), cib_diff)
+        if rc != 0:
+            update_err("cib", cibadmin_opts, cib_diff, rc)
+            return False
+        return True
     #
     # initialize cib_objects from CIB
     #
@@ -2203,21 +2214,30 @@ class CibFactory(Singleton):
         if not self._import_cib():
             return False
         sanitize_cib(self.cib_elem)
+        for attr in self.cib_elem.keys():
+            self.cib_attrs[attr] = self.cib_elem.get(attr)
+        if cibadmin_can_patch():
+            self.cib_orig = \
+                str2tmp(etree.tostring(self.cib_elem, pretty_print=True), \
+                suffix=".xml")
         show_unrecognized_elems(self.cib_elem)
         self._populate()
         return self.check_structure()
     def _init_vars(self):
         self.cib_elem = None  # the cib
+        self.cib_orig = None  # the file holding the CIB which we loaded
         self.cib_attrs = {} # cib version dictionary
         self.cib_objects = [] # a list of cib objects
         self.remove_queue = [] # a list of cib objects to be removed
         self.id_refs = {} # dict of id-refs
-        self.overwrite = False # update cib unconditionally
         self.new_schema = False # schema changed
     def reset(self):
         if self.cib_elem is None:
             return
         self.cib_elem = None
+        if self.cib_orig:
+            try: os.unlink(self.cib_orig)
+            except: pass
         self._init_vars()
         id_store.clear()
     def find_object(self, obj_id):
diff -r 186677999fcd -r c60a0e246836 modules/cibstatus.py
--- a/modules/cibstatus.py	Wed Jun 26 14:43:52 2013 +0200
+++ b/modules/cibstatus.py	Wed Jun 26 14:49:08 2013 +0200
@@ -104,7 +104,7 @@ class CibStatus(Singleton):
     def _load_cib(self, source):
         if source == "live":
             if not self.backing_file:
-                self.backing_file = cib2tmp()
+                self.backing_file = cibdump2tmp()
                 if not self.backing_file:
                     return None
             else:
diff -r 186677999fcd -r c60a0e246836 modules/msg.py
--- a/modules/msg.py	Wed Jun 26 14:43:52 2013 +0200
+++ b/modules/msg.py	Wed Jun 26 14:49:08 2013 +0200
@@ -153,11 +153,15 @@ def update_err(obj_id, cibadm_opt, xml, 
         task = "update"
     elif cibadm_opt == '-D':
         task = "delete"
+    elif cibadm_opt == '-P':
+        task = "patch"
     else:
         task = "replace"
-    err_buf.error("could not %s %s"%(task, obj_id))
+    err_buf.error("could not %s %s (rc=%d)" % (task, obj_id, rc))
     if rc == 54:
         err_buf.info("Permission denied.")
+    elif task == "patch":
+        err_buf.info("offending xml diff: %s" % xml)
     else:
         err_buf.info("offending xml: %s" % xml)
 
diff -r 186677999fcd -r c60a0e246836 modules/ui.py.in
--- a/modules/ui.py.in	Wed Jun 26 14:43:52 2013 +0200
+++ b/modules/ui.py.in	Wed Jun 26 14:49:08 2013 +0200
@@ -332,7 +332,7 @@ class CibShadow(UserInterface):
         if not is_filename_sane(name):
             return False
         if ext_cmd("%s -C '%s' --force" % (self.extcmd, name)) == 0:
-            common_info("commited '%s' shadow CIB to the cluster"%name)
+            common_info("committed '%s' shadow CIB to the cluster"%name)
         else:
             common_err("failed to commit the %s shadow CIB"%name)
             return False
@@ -1768,9 +1768,9 @@ class CibConfig(UserInterface):
             return cib_factory.commit()
         if force or user_prefs.get_force():
             common_info("commit forced")
-            return cib_factory.commit(True)
+            return cib_factory.commit(force=True)
         if ask("Do you still want to commit?"):
-            return cib_factory.commit(True)
+            return cib_factory.commit(force=True)
         return False
     def upgrade(self, cmd, force=None):
         "usage: upgrade [force]"
diff -r 186677999fcd -r c60a0e246836 modules/utils.py
--- a/modules/utils.py	Wed Jun 26 14:43:52 2013 +0200
+++ b/modules/utils.py	Wed Jun 26 14:49:08 2013 +0200
@@ -183,12 +183,12 @@ def filter_string(cmd, s, stderr_on=True
         common_info("from: %s" % cmd)
     return rc, outp
 
-def str2tmp(s):
+def str2tmp(s, suffix=".pcmk"):
     '''
     Write the given string to a temporary file. Return the name
     of the file.
     '''
-    fd, tmp = mkstemp(suffix=".pcmk")
+    fd, tmp = mkstemp(suffix=suffix)
     try:
         f = os.fdopen(fd,"w")
     except IOError, msg:
@@ -869,7 +869,7 @@ def get_cib_attributes(cib_f, tag, attr_
     f.close()
     return val_l
 
-def is_pcmk_118(cib_f=None):
+def is_min_pcmk_ver(min_ver, cib_f=None):
     if not vars.pcmk_version:
         if cib_f:
             vars.pcmk_version = get_cib_property(cib_f, "dc-version", "1.1.1")
@@ -878,7 +878,12 @@ def is_pcmk_118(cib_f=None):
         else:
             vars.pcmk_version = get_pcmk_version("1.1.1")
     from distutils.version import LooseVersion
-    return LooseVersion(vars.pcmk_version) >= LooseVersion("1.1.8")
+    return LooseVersion(vars.pcmk_version) >= LooseVersion(min_ver)
+def is_pcmk_118(cib_f=None):
+    return is_min_pcmk_ver("1.1.8", cib_f=cib_f)
+def cibadmin_can_patch():
+    return True
+    #return is_min_pcmk_ver("1.1.10")
 
 user_prefs = UserPrefs.getInstance()
 options = Options.getInstance()
diff -r 186677999fcd -r c60a0e246836 modules/xmlutil.py
--- a/modules/xmlutil.py	Wed Jun 26 14:43:52 2013 +0200
+++ b/modules/xmlutil.py	Wed Jun 26 14:49:08 2013 +0200
@@ -55,7 +55,7 @@ def cibdump2file(fname):
         common_err(msg)
         return None
     return str2file(s, fname)
-def cib2tmp():
+def cibdump2tmp():
     cmd = add_sudo(cib_dump)
     p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
     try:
_______________________________________________
Linux-HA mailing list
[email protected]
http://lists.linux-ha.org/mailman/listinfo/linux-ha
See also: http://linux-ha.org/ReportingProblems

Reply via email to