Skip to content

Commit ecc653f

Browse files
committed
CA-416486: leaf coalesce wait for GC
In coalesce leaf, after triggering the regular GC, ensure it has completed before proceeding with the VM suspend. Signed-off-by: Mark Syms <mark.syms@citrix.com>
1 parent af8feb5 commit ecc653f

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

libs/sm/cleanup.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,6 +3356,11 @@ def stop_gc_service(sr_uuid):
33563356
util.SMlog(f"Failed to stop gc service `SMGC@{sr_uuid}`: `{stderr}`")
33573357

33583358

3359+
def wait_for_completion(sr_uuid):
3360+
while get_state(sr_uuid):
3361+
time.sleep(5)
3362+
3363+
33593364
def gc_force(session, srUuid, force=False, dryRun=False, lockSR=False):
33603365
"""Garbage collect all deleted VDIs in SR "srUuid". The caller must ensure
33613366
the SR lock is held.

scripts/plugins/coalesce-leaf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ def vm_leaf_coalesce(session, vm_uuid):
183183
# do regular GC now to minimize downtime
184184
cleanup.run_gc(session, sr_uuid, False, immediate=True)
185185

186+
for sr_uuid in coalesceable_vdis:
187+
# wait for the GC process for this SR to complete
188+
cleanup.wait_for_completion(sr_uuid)
189+
186190
suspended = False
187191
if vm_rec["power_state"] == "Running":
188192
log_msg("Suspending VM %s" % vm_rec["uuid"])

tests/test_cleanup.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import errno
22
import signal
3+
import subprocess
34
import unittest
45
import unittest.mock as mock
56
import uuid
@@ -2102,3 +2103,52 @@ def forgetVdi(self, uuid):
21022103
self.xapi_mock.forgetVDI.side_effect = forgetVdi
21032104

21042105
self.mock_sr._finishInterruptedCoalesceLeaf(child_vdi_uuid, parent_vdi_uuid)
2106+
2107+
2108+
class TestService(unittest.TestCase):
2109+
2110+
def setUp(self):
2111+
self.addCleanup(mock.patch.stopall)
2112+
run_patcher = mock.patch("sm.cleanup.subprocess.run", autospec=True)
2113+
self.mock_run = run_patcher.start()
2114+
2115+
sleep_patcher = mock.patch("sm.cleanup.time.sleep", autospec=True)
2116+
self.mock_sleep = sleep_patcher.start()
2117+
2118+
def test_wait_for_completion_noop(self):
2119+
# Arrange
2120+
sr_uuid = str(uuid4())
2121+
sr_uuid_esc = sr_uuid.replace("-", "\\x2d")
2122+
self.mock_run.return_value = subprocess.CompletedProcess("", 0, b"unknown")
2123+
2124+
# Act
2125+
cleanup.wait_for_completion(sr_uuid)
2126+
2127+
# Assert
2128+
self.mock_run.assert_called_once_with(
2129+
["/usr/bin/systemctl", "is-active", f"SMGC@{sr_uuid_esc}"],
2130+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
2131+
2132+
def test_wait_for_completion_wait_2(self):
2133+
# Arrange
2134+
sr_uuid = str(uuid4())
2135+
sr_uuid_esc = sr_uuid.replace("-", "\\x2d")
2136+
2137+
activating_process = subprocess.CompletedProcess("", 0, b"activating")
2138+
finished_process = subprocess.CompletedProcess("", 0, b"unknown")
2139+
self.mock_run.side_effect = [activating_process, activating_process, finished_process]
2140+
2141+
# Act
2142+
cleanup.wait_for_completion(sr_uuid)
2143+
2144+
# Assert
2145+
self.mock_run.assert_has_calls([
2146+
mock.call(
2147+
["/usr/bin/systemctl", "is-active", f"SMGC@{sr_uuid_esc}"],
2148+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True),
2149+
mock.call(
2150+
["/usr/bin/systemctl", "is-active", f"SMGC@{sr_uuid_esc}"],
2151+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True),
2152+
mock.call(
2153+
["/usr/bin/systemctl", "is-active", f"SMGC@{sr_uuid_esc}"],
2154+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)])

0 commit comments

Comments
 (0)