XenAPI: run vhd-util repair if VHD check fails

We can hit issues with corrupted VHDs if we copy a VHD while XenServer
is performing other operations. This happens because there are times
when we copy the VHD chains while XenServer is still performing a
coalesce of the VHD chain.

In most cases, vhd-util should be able to safely repair any metadata
corruption. It can copy the copy of the VHD footer at the front of the
VHD file and add it at the bottom on the VHD file. There is no VM data
loss, due to the way the coalesce happens, but the chain will be bigger
than it would be both before and after the coalesce.

This does not, however, ensure that snapshots are valid before uploading
them to glance. But should you launch a corrupted snapshot, this change
would fix up the snapshot, and allow it to boot correctly.

Closes-Bug: #1362595

Change-Id: I88b737d7e97964a9db5ccf2c39dea7fd0701ead4
This commit is contained in:
John Garbutt 2014-08-26 17:05:58 +01:00
parent 48b6af7169
commit bfdae32efb

View File

@ -214,6 +214,13 @@ def _assert_vhd_not_hidden(path):
"VHD %s is marked as hidden without child" % path)
def _vhd_util_check(vdi_path):
check_cmd = ["vhd-util", "check", "-n", vdi_path, "-p"]
out = run_command(check_cmd, ok_exit_codes=[0, 22])
first_line = out.splitlines()[0].strip()
return out, first_line
def _validate_vhd(vdi_path):
"""This checks for several errors in the VHD structure.
@ -225,9 +232,13 @@ def _validate_vhd(vdi_path):
Dom0's are out-of-sync. This would corrupt the SR if it were imported, so
generate an exception to bail.
"""
check_cmd = ["vhd-util", "check", "-n", vdi_path, "-p"]
out = run_command(check_cmd, ok_exit_codes=[0, 22])
first_line = out.splitlines()[0].strip()
out, first_line = _vhd_util_check(vdi_path)
if 'invalid' in first_line:
LOG.warning("VHD invalid, attempting repair.")
repair_cmd = ["vhd-util", "repair", "-n", vdi_path]
run_command(repair_cmd)
out, first_line = _vhd_util_check(vdi_path)
if 'invalid' in first_line:
if 'footer' in first_line:
@ -255,6 +266,8 @@ def _validate_vhd(vdi_path):
"%(extra)s" % {'vdi_path': vdi_path, 'part': part,
'details': details, 'extra': extra})
LOG.info("VDI is valid: %s" % vdi_path)
def _validate_vdi_chain(vdi_path):
"""This check ensures that the parent pointers on the VHDs are valid