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:
parent
65fedbdd9a
commit
4b38f3e59b
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user