Fixes Hyper-V issue with VHD file format

The VHD format cookie signature needs to be checked in the footer
instead of the header as fixed format VHDs don't have a copy of the
footer at the beginning of the file.

Fixes bug: #1233853

(cherry-picked from commit fdc5a57d03)

Conflicts:

	nova/tests/virt/hyperv/test_vhdutils.py

Change-Id: Ibe44f0d895cde2edbc03dcd6ecebac24b0936660
This commit is contained in:
Alessandro Pilotti 2013-10-02 00:39:09 +03:00 committed by Lucian Petrut
parent 65fedbdd9a
commit 4b38f3e59b
2 changed files with 70 additions and 7 deletions

View File

@ -88,3 +88,47 @@ class VHDUtilsTestCase(test.NoDBTestCase):
self.assertRaises(vmutils.HyperVException,
vhdutil.get_internal_vhd_size_by_file_size,
None, root_vhd_size)
def test_get_vhd_format_vhdx(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data=vhdutils.VHDX_SIGNATURE),
create=True) as mock_open:
format = self._vhdutils.get_vhd_format(self._FAKE_VHD_PATH)
self.assertEqual(constants.DISK_FORMAT_VHDX, format)
def test_get_vhd_format_vhd(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data=vhdutils.VHD_SIGNATURE),
create=True) as mock_open:
f = mock_open.return_value
f.tell.return_value = 1024
format = self._vhdutils.get_vhd_format(self._FAKE_VHD_PATH)
self.assertEqual(constants.DISK_FORMAT_VHD, format)
def test_get_vhd_format_invalid_format(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data='invalid'),
create=True) as mock_open:
f = mock_open.return_value
f.tell.return_value = 1024
self.assertRaises(vmutils.HyperVException,
self._vhdutils.get_vhd_format,
self._FAKE_VHD_PATH)
def test_get_vhd_format_zero_length_file(self):
with mock.patch('nova.virt.hyperv.vhdutils.open',
mock.mock_open(read_data=''),
create=True) as mock_open:
f = mock_open.return_value
f.tell.return_value = 0
self.assertRaises(vmutils.HyperVException,
self._vhdutils.get_vhd_format,
self._FAKE_VHD_PATH)
f.seek.assert_called_once_with(0, 2)

View File

@ -15,6 +15,16 @@
# License for the specific language governing permissions and limitations
# under the License.
"""
Utility class for VHD related operations.
Official VHD format specs can be retrieved at:
http://technet.microsoft.com/en-us/library/bb676673.aspx
See "Download the Specifications Without Registering"
Official VHDX format specs can be retrieved at:
http://www.microsoft.com/en-us/download/details.aspx?id=34750
"""
import struct
import sys
@ -34,6 +44,9 @@ VHD_HEADER_SIZE_DYNAMIC = 512
VHD_FOOTER_SIZE_DYNAMIC = 512
VHD_BLK_SIZE_OFFSET = 544
VHD_SIGNATURE = 'conectix'
VHDX_SIGNATURE = 'vhdxfile'
class VHDUtils(object):
@ -178,13 +191,19 @@ class VHDUtils(object):
def get_vhd_format(self, path):
with open(path, 'rb') as f:
signature = f.read(8)
if signature == 'vhdxfile':
return constants.DISK_FORMAT_VHDX
elif signature == 'conectix':
return constants.DISK_FORMAT_VHD
else:
raise vmutils.HyperVException(_('Unsupported virtual disk format'))
# Read header
if f.read(8) == VHDX_SIGNATURE:
return constants.DISK_FORMAT_VHDX
# Read footer
f.seek(0, 2)
file_size = f.tell()
if file_size >= 512:
f.seek(-512, 2)
if f.read(8) == VHD_SIGNATURE:
return constants.DISK_FORMAT_VHD
raise vmutils.HyperVException(_('Unsupported virtual disk format'))
def get_best_supported_vhd_format(self):
return constants.DISK_FORMAT_VHD