Skip to content

Commit f513b33

Browse files
committed
SR.scan: mark gone VDIs missing instead of forgetting
SR.scan used to forget gone VDI, so during a later scan it recover and dropped name-label and snapshot metadata. Mark gone VDIs missing instead (like ISOSR), and clear the flag when they are on disk again. Signed-off-by: Erwan Croze <erwan.croze@vates.tech>
1 parent d51b439 commit f513b33

2 files changed

Lines changed: 78 additions & 3 deletions

File tree

libs/sm/SR.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,12 +596,13 @@ def synchronise_new(self):
596596
vdi._db_introduce()
597597

598598
def synchronise_gone(self):
599-
"""Delete XenAPI record for old disks"""
599+
"""Mark XenAPI records missing for old disks"""
600600
for location in self.gone:
601601
vdi = self.get_xenapi_vdi(location)
602-
util.SMlog("Forgetting VDI with location=%s uuid=%s" % (util.to_plain_string(vdi['location']), vdi['uuid']))
602+
util.SMlog("Marking VDI as missing: location=%s uuid=%s" %
603+
(util.to_plain_string(vdi['location']), vdi['uuid']))
603604
try:
604-
self.sr.forget_vdi(vdi['uuid'])
605+
self.sr.session.xenapi.VDI.set_missing(self.sr.session.xenapi.VDI.get_by_uuid(vdi['uuid']), True)
605606
except XenAPI.Failure as e:
606607
if util.isInvalidVDI(e):
607608
util.SMlog("VDI %s not found, ignoring exception" %
@@ -617,9 +618,31 @@ def synchronise_existing(self):
617618
util.SMlog("Updating VDI with location=%s uuid=%s" % (vdi.location, vdi.uuid))
618619
vdi._db_update()
619620

621+
def _clear_missing_vdi(self):
622+
"""Clear missing flag for VDIs present on disk again"""
623+
for location in self.all_xenapi_locations():
624+
try:
625+
self.get_sm_vdi(location)
626+
except KeyError:
627+
continue
628+
vdi = self.get_xenapi_vdi(location)
629+
if not vdi.get('missing'):
630+
continue
631+
util.SMlog("Clearing missing flag: location=%s uuid=%s" %
632+
(util.to_plain_string(location), vdi['uuid']))
633+
try:
634+
self.sr.session.xenapi.VDI.set_missing(self.sr.session.xenapi.VDI.get_by_uuid(vdi['uuid']), False)
635+
except XenAPI.Failure as e:
636+
if util.isInvalidVDI(e):
637+
util.SMlog("VDI %s not found, ignoring exception" %
638+
vdi['uuid'])
639+
else:
640+
raise
641+
620642
def synchronise(self):
621643
"""Perform the default SM -> xenapi synchronisation; ought to be good enough
622644
for most plugins."""
623645
self.synchronise_new()
624646
self.synchronise_gone()
625647
self.synchronise_existing()
648+
self._clear_missing_vdi()

tests/test_SR.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,55 @@ def test_after_master_attach_vdi_not_available(
8686
mock_log.call_args[0][0])
8787
mock_session.xenapi.message.create.assert_called_once_with(
8888
"POST_ATTACH_SCAN_FAILED", 2, 'SR', 'dummy uuid', mock.ANY)
89+
90+
def test_synchronise_gone_marks_missing(self):
91+
sr = mock.MagicMock()
92+
session = sr.session
93+
vdi_ref = 'OpaqueRef:vdi'
94+
session.xenapi.VDI.get_by_uuid.return_value = vdi_ref
95+
96+
record = mock.Mock()
97+
record.sr = sr
98+
record.gone = {'gone-location'}
99+
record.get_xenapi_vdi.return_value = {
100+
'location': 'gone-location',
101+
'uuid': 'vdi-uuid',
102+
}
103+
104+
SR.ScanRecord.synchronise_gone(record)
105+
106+
session.xenapi.VDI.set_missing.assert_called_once_with(vdi_ref, True)
107+
sr.forget_vdi.assert_not_called()
108+
109+
def test_clear_missing_vdi_when_present(self):
110+
sr = mock.MagicMock()
111+
session = sr.session
112+
vdi_ref = 'OpaqueRef:vdi'
113+
session.xenapi.VDI.get_by_uuid.return_value = vdi_ref
114+
115+
record = mock.Mock()
116+
record.sr = sr
117+
record.all_xenapi_locations.return_value = {'present-location'}
118+
record.get_sm_vdi.return_value = mock.Mock()
119+
record.get_xenapi_vdi.return_value = {
120+
'location': 'present-location',
121+
'uuid': 'vdi-uuid',
122+
'missing': True,
123+
}
124+
125+
SR.ScanRecord._clear_missing_vdi(record)
126+
127+
session.xenapi.VDI.set_missing.assert_called_once_with(vdi_ref, False)
128+
129+
def test_clear_missing_vdi_skips_gone(self):
130+
sr = mock.MagicMock()
131+
session = sr.session
132+
133+
record = mock.Mock()
134+
record.sr = sr
135+
record.all_xenapi_locations.return_value = {'gone-location'}
136+
record.get_sm_vdi.side_effect = KeyError('gone-location')
137+
138+
SR.ScanRecord._clear_missing_vdi(record)
139+
140+
session.xenapi.VDI.set_missing.assert_not_called()

0 commit comments

Comments
 (0)