From: Chandrika Srinivasan <chandrika.srinivasan@citrix.com>
Date: Thu, 12 Apr 2018 15:26:20 +0100
CA-287883: Refresh CBT log LV on slave after snapshot

Snapshotting a CBT enabled VDI renames the associated CBT log file. Refresh
and reactivate CBT log file on slaves in such cases. 

Signed-off-by: Chandrika Srinivasan <chandrika.srinivasan@citrix.com>
diff --git a/drivers/LVHDSR.py b/drivers/LVHDSR.py
index ef7afff..e6a76b6 100755
--- a/drivers/LVHDSR.py
+++ b/drivers/LVHDSR.py
@@ -1245,6 +1245,25 @@ class LVHDSR(SR.SR):
             if not rv:
                 raise Exception('plugin %s failed' % self.PLUGIN_ON_SLAVE)
 
+    def _updateSlavesOnCBTClone(self, hostRefs, cbtlog):
+        """Reactivate and refresh CBT log file on slaves"""
+        args = {"vgName" : self.vgname,
+                "action1": "deactivateNoRefcount",
+                "lvName1": cbtlog,
+                "action2": "refresh",
+                "lvName2": cbtlog}
+
+        masterRef = util.get_this_host_ref(self.session)
+        for hostRef in hostRefs:
+            if hostRef == masterRef:
+                continue
+            util.SMlog("Updating %s on slave %s" % (cbtlog, hostRef))
+            rv = eval(self.session.xenapi.host.call_plugin(
+                    hostRef, self.PLUGIN_ON_SLAVE, "multi", args))
+            util.SMlog("call-plugin returned: %s" % rv)
+            if not rv:
+                raise Exception('plugin %s failed' % self.PLUGIN_ON_SLAVE)
+
     def _updateSlavesOnRemove(self, hostRefs, baseUuid, baseLV):
         """Tell the slave we deleted the base image"""
         args = {"vgName" : self.vgname,
@@ -1800,6 +1819,16 @@ class LVHDVDI(VDI.VDI):
             # Update cbt files if user created snapshot (SNAPSHOT_DOUBLE)
             if snapType == VDI.SNAPSHOT_DOUBLE and cbtlog:
                 snapVDI._cbt_snapshot(clonUuid, cbt_consistency)
+                if hostRefs:
+                    cbtlog_file = self._get_cbt_logname(snapVDI.uuid)
+                    try:
+                        self.sr._updateSlavesOnCBTClone(hostRefs, cbtlog_file)
+                    except:
+                        alert_name = "VDI_CBT_SNAPSHOT_FAILED"
+                        alert_str = ("Creating CBT snapshot for {} failed"
+                                     .format(snapVDI.uuid))
+                        snapVDI._disable_cbt_on_error(alert_name, alert_str)
+                        pass
 
         except (util.SMException, XenAPI.Failure), e:
             util.logException("LVHDVDI._snapshot")
diff --git a/drivers/VDI.py b/drivers/VDI.py
index c73cc92..ff88342 100755
--- a/drivers/VDI.py
+++ b/drivers/VDI.py
@@ -298,21 +298,10 @@ class VDI(object):
                 logpath = self._get_cbt_logpath(vdi_uuid)
                 self._cbt_op(vdi_uuid, cbtutil.set_cbt_size, logpath, size)
         except util.CommandException as ex:
-            util.SMlog("Resizing of log file %s failed, "
-                       "disabling CBT. Reason: %s" % (logpath, str(ex)))
-            self._delete_cbt_log()
-            vdi_ref = self.sr.srcmd.params['vdi_ref']
-            self.sr.session.xenapi.VDI.set_cbt_enabled(vdi_ref, False)
             alert_name = "VDI_CBT_RESIZE_FAILED"
-            alert_prio_warning = "3"
-            alert_obj = "VDI"
-            alert_uuid = str(vdi_uuid)
             alert_str = ("Resizing of CBT metadata for disk %s failed."
                          % vdi_uuid)
-            self.sr.session.xenapi.message.create(alert_name,
-                                                  alert_prio_warning,
-                                                  alert_obj, alert_uuid,
-                                                  alert_str)
+            self._disable_cbt_on_error(alert_name, alert_str)
 
     def delete(self, sr_uuid, vdi_uuid, data_only=False):
         """Delete this VDI.
@@ -451,24 +440,10 @@ class VDI(object):
             consistent = self._cbt_op(vdi_uuid, cbtutil.get_cbt_consistency,
                                       logpath)
             if not consistent:
-                lock.acquire()
-                try:
-                    self._delete_cbt_log()
-                finally:
-                    lock.release()
-                vdi_ref = self.sr.srcmd.params['vdi_ref']
-                self.sr.session.xenapi.VDI.set_cbt_enabled(vdi_ref, False)
                 alert_name = "VDI_CBT_METADATA_INCONSISTENT"
-                alert_prio_warning = "3"
-                alert_obj = "VDI"
-                alert_uuid = str(vdi_uuid)
                 alert_str = ("Changed Block Tracking metadata is inconsistent"
                              " for disk %s." % vdi_uuid)
-                util.SMlog(alert_str)
-                self.sr.session.xenapi.message.create(alert_name,
-                                                      alert_prio_warning,
-                                                      alert_obj, alert_uuid,
-                                                      alert_str)
+                self._disable_cbt_on_error(alert_name, alert_str)
                 return None
 
             self._cbt_op(self.uuid, cbtutil.set_cbt_consistency,
@@ -828,21 +803,11 @@ class VDI(object):
             self._cbt_op(snapshot_uuid, cbtutil.set_cbt_child,
                          snap_logpath, self.uuid)
         except Exception as ex:
-            self._delete_cbt_log() 
-            vdi_ref = self.sr.srcmd.params['vdi_ref']
-            self.sr.session.xenapi.VDI.set_cbt_enabled(vdi_ref, False)
-            util.SMlog("Creating the Changed Block Tracking log file failed. "
-                       "Reason: %s" % str(ex))
             alert_name = "VDI_CBT_SNAPSHOT_FAILED"
-            alert_prio_warning = "3"
-            alert_obj = "VDI"
-            alert_uuid = str(self.uuid)
             alert_str = ("Creating CBT metadata log for disk %s failed."
                          % self.uuid)
-            self.sr.session.xenapi.message.create(alert_name,
-                                                  alert_prio_warning,
-                                                  alert_obj, alert_uuid,
-                                                  alert_str)
+            self._disable_cbt_on_error(alert_name, alert_str)
+
 
     def _get_blocktracking_status(self, uuid=None):
         """ Get blocktracking status """
@@ -929,3 +894,16 @@ class VDI(object):
             return ret
         finally:
             lock.release()
+
+    def _disable_cbt_on_error(self, alert_name, alert_str):
+        util.SMlog(alert_str)
+        self._delete_cbt_log()
+        vdi_ref = self.sr.srcmd.params['vdi_ref']
+        self.sr.session.xenapi.VDI.set_cbt_enabled(vdi_ref, False)
+        alert_prio_warning = "3"
+        alert_obj = "VDI"
+        alert_uuid = str(self.uuid)
+        self.sr.session.xenapi.message.create(alert_name,
+                                              alert_prio_warning,
+                                              alert_obj, alert_uuid,
+                                              alert_str)
