Skip to content

Commit 465f951

Browse files
authored
metadata: improve error messages when vdi_type is missing (#103)
Explicit error message pointing to missing vdi_type on SRMetadata update Add a distinction for unpacking corrupted empty metadata headers for easier diagnostic Signed-off-by: Antoine Bartuccio <antoine.bartuccio@vates.tech>
1 parent 56a5eeb commit 465f951

4 files changed

Lines changed: 62 additions & 10 deletions

File tree

drivers/LVHDSR.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ def updateSRMetadata(self, allocation):
262262
for vdi in self.session.xenapi.SR.get_VDIs(self.sr_ref):
263263
vdi_uuid = self.session.xenapi.VDI.get_uuid(vdi)
264264

265+
vdi_type = self.session.xenapi.VDI.get_sm_config(vdi).get('vdi_type')
266+
if not vdi_type:
267+
raise xs_errors.XenError('MetadataError', opterr=f"Missing `vdi_type` for VDI {vdi_uuid}")
268+
265269
# Create the VDI entry in the SR metadata
266270
vdi_info[vdi_uuid] = \
267271
{
@@ -277,7 +281,7 @@ def updateSRMetadata(self, allocation):
277281
TYPE_TAG: \
278282
self.session.xenapi.VDI.get_type(vdi),
279283
VDI_TYPE_TAG: \
280-
self.session.xenapi.VDI.get_sm_config(vdi)['vdi_type'],
284+
vdi_type,
281285
READ_ONLY_TAG: \
282286
int(self.session.xenapi.VDI.get_read_only(vdi)),
283287
METADATA_OF_POOL_TAG: \

drivers/srmetadata.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# Functions to read and write SR metadata
1717
#
1818

19-
from sm_typing import ClassVar, override
19+
from sm_typing import ClassVar, Tuple, override
2020

2121
from abc import abstractmethod
2222

@@ -138,11 +138,11 @@ def file_read_wrapper(fd, offset, bytesToRead=METADATA_BLK_SIZE):
138138
([fd, offset, bytesToRead], e.errno))
139139

140140

141-
def to_utf8(s):
141+
def to_utf8(s: str) -> bytes:
142142
return s.encode("utf-8")
143143

144144

145-
def from_utf8(bs):
145+
def from_utf8(bs: bytes) -> str:
146146
return bs.decode("utf-8")
147147

148148

@@ -182,13 +182,14 @@ def buildHeader(length, major=metadata.MD_MAJOR, minor=metadata.MD_MINOR):
182182
+ str(minor))
183183

184184

185-
def unpackHeader(header):
186-
vals = from_utf8(header).split(HEADER_SEP)
185+
def unpackHeader(header: bytes) -> Tuple[str, str, str, str]:
186+
decoded = from_utf8(header)
187+
if len(decoded.rstrip('\x00')) == 0:
188+
raise xs_errors.XenError('MetadataError', opterr='Empty header')
189+
vals = decoded.split(HEADER_SEP)
187190
if len(vals) != 4 or vals[0] != metadata.HDR_STRING:
188-
util.SMlog("Exception unpacking metadata header: "
189-
"Error: Bad header '%s'" % (header))
190-
raise xs_errors.XenError('MetadataError', \
191-
opterr='Bad header')
191+
util.SMlog(f"Exception unpacking metadata header: Error: Bad header {header!r}")
192+
raise xs_errors.XenError('MetadataError', opterr='Bad header')
192193
return (vals[0], vals[1], vals[2], vals[3])
193194

194195

tests/test_LVHDSR.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,16 @@ def cmd(args):
279279
self.assertEqual(1, lvm_cache.activate.call_count)
280280
self.assertEqual(1, lvm_cache.deactivate.call_count)
281281

282+
# Act (3)
283+
# This tests SR metadata updates
284+
sr.updateSRMetadata('thick')
285+
286+
# Test that removing vdi_type on a vdi does crash properly
287+
del vdi_data['vdi2_ref']['sm-config']['vdi_type']
288+
with self.assertRaises(Exception):
289+
# Fail on vdi2_ref
290+
sr.updateSRMetadata('thick')
291+
282292
def convert_vdi_to_meta(self, vdi_data):
283293
metadata = {}
284294
for item in vdi_data.items():

tests/test_srmetadata.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import uuid
88
import unittest
99
import unittest.mock as mock
10+
import xs_errors
1011

1112
from srmetadata import (LVMMetadataHandler, buildHeader, buildXMLSector,
1213
getMetadataLength, unpackHeader, updateLengthInHeader,
@@ -27,6 +28,42 @@ def test_unpackHeader(self):
2728
self.assertEqual(int(major), 1)
2829
self.assertEqual(int(minor), 2)
2930

31+
def test_unpackHeader_empty(self):
32+
# Given
33+
headers = [b"", b"\x00", b"\x00"]
34+
35+
for header in headers:
36+
# When
37+
with self.assertRaises(xs_errors.SROSError) as error:
38+
unpackHeader(header)
39+
40+
# Then
41+
self.assertEqual(
42+
error.exception.args[0],
43+
'Error in Metadata volume operation for SR. [opterr=Empty header]'
44+
)
45+
46+
def test_unpackHeader_bad(self):
47+
# Given
48+
headers = [
49+
b"BAD:4096 :1:2" + (b' ' * 493),
50+
b"BAD:4096 :1:2",
51+
b"XSSM:4096 :1",
52+
b"XSSM:4096 ",
53+
b"XSSM",
54+
]
55+
56+
for header in headers:
57+
# When
58+
with self.assertRaises(xs_errors.SROSError) as error:
59+
unpackHeader(header)
60+
61+
# Then
62+
self.assertEqual(
63+
error.exception.args[0],
64+
'Error in Metadata volume operation for SR. [opterr=Bad header]'
65+
)
66+
3067
def test_buildHeader_unpackHeader_roundTrip(self):
3168
# Given
3269
orig_length = 12345

0 commit comments

Comments
 (0)