Validate VDI chain before moving into SR.

Fixes bug 949477

Change-Id: Ia3f283d82f189e680c5c8dd4fcf71bf5fe5f9889
This commit is contained in:
Rick Harris 2012-03-08 01:26:04 +00:00
parent 70f0ea588e
commit 1da6a00a3b

View File

@ -265,6 +265,34 @@ def _import_vhds(sr_path, staging_path, uuid_stack):
link_vhds(new_path, parent_path)
return (new_path, vdi_uuid)
def validate_vdi_chain(vdi_path):
"""
This check ensures that the parent pointers on the VHDs are valid
before we move the VDI chain to the SR. This is *very* important
because a bad parent pointer will corrupt the SR causing a cascade of
failures.
"""
def get_parent_path(path):
query_cmd = "vhd-util query -n %(path)s -p" % locals()
query_proc = _make_subprocess(query_cmd, stdout=True, stderr=True)
out, err = _finish_subprocess(
query_proc, query_cmd, ok_exit_codes=[0, 22])
first_line = out.splitlines()[0].strip()
if first_line.endswith(".vhd"):
return first_line
elif 'has no parent' in first_line:
return None
elif 'query failed' in first_line:
raise Exception("VDI '%(path)s' not present which breaks"
" the VDI chain, bailing out" % locals())
else:
raise Exception("Unexpected output '%(out)s' from vhd-util" %
locals())
cur_path = vdi_path
while cur_path:
cur_path = get_parent_path(cur_path)
vdi_return_list = []
paths_to_move = []
@ -283,6 +311,7 @@ def _import_vhds(sr_path, staging_path, uuid_stack):
snap_info = prepare_if_exists(staging_path, 'snap.vhd',
image_info[0])
if snap_info:
validate_vdi_chain(snap_info[0])
# NOTE(sirp): this is an insert rather than an append since the
# 'snapshot' vhd needs to be copied into the SR before the base copy.
# If it doesn't, then there is a possibliity that snapwatchd will
@ -291,6 +320,7 @@ def _import_vhds(sr_path, staging_path, uuid_stack):
# We return this snap as the VDI instead of image.vhd
vdi_return_list.append(dict(vdi_type="os", vdi_uuid=snap_info[1]))
else:
validate_vdi_chain(image_info[0])
assert_vhd_not_hidden(image_info[0])
# If there's no snap, we return the image.vhd UUID
vdi_return_list.append(dict(vdi_type="os", vdi_uuid=image_info[1]))
@ -439,14 +469,18 @@ def _make_subprocess(cmdline, stdout=False, stderr=False, stdin=False):
return proc
def _finish_subprocess(proc, cmdline):
def _finish_subprocess(proc, cmdline, ok_exit_codes=None):
"""Ensure that the process returned a zero exit code indicating success
"""
if ok_exit_codes is None:
ok_exit_codes = [0]
out, err = proc.communicate()
ret = proc.returncode
if ret != 0:
if ret not in ok_exit_codes:
raise Exception("'%(cmdline)s' returned non-zero exit code: "
"retcode=%(ret)i, stderr='%(err)s'" % locals())
"retcode=%(ret)i, out='%(out)s', stderr='%(err)s'"
% locals())
return out, err