Skip to content

Commit 91c26bb

Browse files
committed
CA-421013: ensure cbt log removed on supporter after disable
When CBT is disabled the CBT log is deleted, on the coordinator, when using shared LVM SRs it is necessary to inform the supporter of this change so that it can remove all information relating to the CBT log volume from the kernel device mapper table. If this is not done a subsequent CBT enable for this VDI will fail if the device mapper table still contains information about the previous, and now deleted, volume. Signed-off-by: Mark Syms <[email protected]>
1 parent 527db10 commit 91c26bb

File tree

3 files changed

+70
-40
lines changed

3 files changed

+70
-40
lines changed

libs/sm/VDI.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,10 @@ def in_sync_with_xenapi_record(self, x):
572572
return False
573573
return True
574574

575+
def update_slaves_on_cbt_disable(self, cbtlog):
576+
# Override in implementation as required.
577+
pass
578+
575579
def configure_blocktracking(self, sr_uuid, vdi_uuid, enable):
576580
"""Function for configuring blocktracking"""
577581
from sm import blktap2
@@ -626,6 +630,8 @@ def configure_blocktracking(self, sr_uuid, vdi_uuid, enable):
626630
if self._cbt_log_exists(parent_path):
627631
self._cbt_op(parent, cbtutil.set_cbt_child,
628632
parent_path, uuid.UUID(int=0))
633+
if disk_state:
634+
self.update_slaves_on_cbt_disable(logpath)
629635
except Exception as error:
630636
raise xs_errors.XenError('CBTDeactivateFailed', str(error))
631637
finally:

libs/sm/drivers/LVHDSR.py

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,20 +1197,25 @@ def _undoAllVHDJournals(self):
11971197
delattr(self, "vdiInfo")
11981198
delattr(self, "allVDIs")
11991199

1200-
def _updateSlavesPreClone(self, hostRefs, origOldLV):
1201-
masterRef = util.get_this_host_ref(self.session)
1202-
args = {"vgName": self.vgname,
1203-
"action1": "deactivateNoRefcount",
1204-
"lvName1": origOldLV}
1205-
for hostRef in hostRefs:
1206-
if hostRef == masterRef:
1200+
def call_on_slave(self, args, host_refs, message: str):
1201+
master_ref = util.get_this_host_ref(self.session)
1202+
for hostRef in host_refs:
1203+
if hostRef == master_ref:
12071204
continue
1208-
util.SMlog("Deactivate VDI on %s" % hostRef)
1209-
rv = self.session.xenapi.host.call_plugin(hostRef, self.PLUGIN_ON_SLAVE, "multi", args)
1205+
util.SMlog(f"{message} on slave {hostRef}")
1206+
rv = self.session.xenapi.host.call_plugin(
1207+
hostRef, self.PLUGIN_ON_SLAVE, "multi", args)
12101208
util.SMlog("call-plugin returned: %s" % rv)
12111209
if not rv:
12121210
raise Exception('plugin %s failed' % self.PLUGIN_ON_SLAVE)
12131211

1212+
def _updateSlavesPreClone(self, hostRefs, origOldLV):
1213+
args = {"vgName": self.vgname,
1214+
"action1": "deactivateNoRefcount",
1215+
"lvName1": origOldLV}
1216+
message = "Deactivate VDI"
1217+
self.call_on_slave(args, hostRefs, message)
1218+
12141219
def _updateSlavesOnClone(self, hostRefs, origOldLV, origLV,
12151220
baseUuid, baseLV):
12161221
"""We need to reactivate the original LV on each slave (note that the
@@ -1224,17 +1229,8 @@ def _updateSlavesOnClone(self, hostRefs, origOldLV, origLV,
12241229
"lvName2": baseLV,
12251230
"uuid2": baseUuid}
12261231

1227-
masterRef = util.get_this_host_ref(self.session)
1228-
for hostRef in hostRefs:
1229-
if hostRef == masterRef:
1230-
continue
1231-
util.SMlog("Updating %s, %s, %s on slave %s" % \
1232-
(origOldLV, origLV, baseLV, hostRef))
1233-
rv = self.session.xenapi.host.call_plugin(
1234-
hostRef, self.PLUGIN_ON_SLAVE, "multi", args)
1235-
util.SMlog("call-plugin returned: %s" % rv)
1236-
if not rv:
1237-
raise Exception('plugin %s failed' % self.PLUGIN_ON_SLAVE)
1232+
message = f"Updating {origOldLV}, {origLV}, {baseLV}"
1233+
self.call_on_slave(args, hostRefs, message)
12381234

12391235
def _updateSlavesOnCBTClone(self, hostRefs, cbtlog):
12401236
"""Reactivate and refresh CBT log file on slaves"""
@@ -1244,16 +1240,8 @@ def _updateSlavesOnCBTClone(self, hostRefs, cbtlog):
12441240
"action2": "refresh",
12451241
"lvName2": cbtlog}
12461242

1247-
masterRef = util.get_this_host_ref(self.session)
1248-
for hostRef in hostRefs:
1249-
if hostRef == masterRef:
1250-
continue
1251-
util.SMlog("Updating %s on slave %s" % (cbtlog, hostRef))
1252-
rv = self.session.xenapi.host.call_plugin(
1253-
hostRef, self.PLUGIN_ON_SLAVE, "multi", args)
1254-
util.SMlog("call-plugin returned: %s" % rv)
1255-
if not rv:
1256-
raise Exception('plugin %s failed' % self.PLUGIN_ON_SLAVE)
1243+
message = f"Updating {cbtlog}"
1244+
self.call_on_slave(args, hostRefs, message)
12571245

12581246
def _updateSlavesOnRemove(self, hostRefs, baseUuid, baseLV):
12591247
"""Tell the slave we deleted the base image"""
@@ -1262,16 +1250,8 @@ def _updateSlavesOnRemove(self, hostRefs, baseUuid, baseLV):
12621250
"uuid1": baseUuid,
12631251
"ns1": lvhdutil.NS_PREFIX_LVM + self.uuid}
12641252

1265-
masterRef = util.get_this_host_ref(self.session)
1266-
for hostRef in hostRefs:
1267-
if hostRef == masterRef:
1268-
continue
1269-
util.SMlog("Cleaning locks for %s on slave %s" % (baseLV, hostRef))
1270-
rv = self.session.xenapi.host.call_plugin(
1271-
hostRef, self.PLUGIN_ON_SLAVE, "multi", args)
1272-
util.SMlog("call-plugin returned: %s" % rv)
1273-
if not rv:
1274-
raise Exception('plugin %s failed' % self.PLUGIN_ON_SLAVE)
1253+
message = f"Cleaning locks for {baseLV}"
1254+
self.call_on_slave(args, hostRefs, message)
12751255

12761256
def _cleanup(self, skipLockCleanup=False):
12771257
"""delete stale refcounter, flag, and lock files"""
@@ -2203,6 +2183,18 @@ def _rename(self, oldpath, newpath):
22032183
newname = os.path.basename(newpath)
22042184
self.sr.lvmCache.rename(oldname, newname)
22052185

2186+
def update_slaves_on_cbt_disable(self, cbtlog):
2187+
args = {
2188+
"vgName": self.sr.vgname,
2189+
"action1": "deactivateNoRefcount",
2190+
"lvName1": cbtlog
2191+
}
2192+
2193+
host_refs = util.get_hosts_attached_on(self.session, [self.uuid])
2194+
2195+
message = f"Deactivating {cbtlog}"
2196+
self.sr.call_on_slave(args, host_refs, message)
2197+
22062198
def _activate_cbt_log(self, lv_name):
22072199
self.sr.lvmCache.refresh()
22082200
if not self.sr.lvmCache.is_active(lv_name):

tests/test_LVHDSR.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,38 @@ def test_snapshot_attached_cbt_success(self, mock_xenapi, mock_lock):
479479
self.assertIsNotNone(snap)
480480
self.assertEqual(self.mock_cbtutil.set_cbt_child.call_count, 3)
481481

482+
@mock.patch('sm.drivers.LVHDSR.Lock', autospec=True)
483+
@mock.patch('sm.drivers.LVHDSR.SR.XenAPI')
484+
def test_update_slaves_on_cbt_disable(self, mock_xenapi, mock_lock):
485+
"""
486+
Ensure we tell the supporter host when we disable CBT for one of its VMs
487+
"""
488+
# Arrange
489+
xapi_session = mock_xenapi.xapi_local.return_value
490+
491+
vdi_uuid = str(uuid.uuid4)
492+
mock_lv = self.get_dummy_vdi(vdi_uuid)
493+
self.get_dummy_vhd(vdi_uuid, False)
494+
495+
sr = self.create_LVHDSR()
496+
sr.isMaster = True
497+
498+
vdi = sr.vdi(vdi_uuid)
499+
vdi.vdi_type = vhdutil.VDI_TYPE_VHD
500+
501+
self.mock_sr_util.get_this_host_ref.return_value = 'ref1'
502+
self.mock_sr_util.get_hosts_attached_on.return_value = ['ref2']
503+
504+
# Act
505+
log_file_path = "test_log_path"
506+
vdi.update_slaves_on_cbt_disable(log_file_path)
507+
508+
# Assert
509+
self.assertEqual(1, xapi_session.xenapi.host.call_plugin.call_count)
510+
xapi_session.xenapi.host.call_plugin.assert_has_calls([
511+
mock.call('ref2', 'on-slave', 'multi', mock.ANY)
512+
])
513+
482514
@mock.patch('sm.drivers.LVHDSR.Lock', autospec=True)
483515
@mock.patch('sm.drivers.LVHDSR.SR.XenAPI')
484516
def test_snapshot_secondary_success(self, mock_xenapi, mock_lock):

0 commit comments

Comments
 (0)