Relax checksum fields validation

In stein, ironic added the new os_hash_algo and os_hash_value checksum
fields provided by glance, but the checksum field is still mandatory,
which is inconvenient for standalone use case.

We could relax the checksum checking and proceed as long as there is at
least one of checksum mechanism available.

Change-Id: Ia90197416f76ada0422681044a16f1c07d7049a1
Story: 2005773
Task: 33490
This commit is contained in:
Kaifeng Wang 2019-05-24 14:30:48 +08:00
parent e30f1d7571
commit a9cac52190
3 changed files with 77 additions and 6 deletions

View File

@ -268,9 +268,18 @@ class ImageDownload(object):
if algo and algo in hashlib.algorithms_available:
self._hash_algo = hashlib.new(algo)
self._expected_hash_value = image_info.get('os_hash_value')
else:
elif image_info.get('checksum'):
self._hash_algo = hashlib.md5()
self._expected_hash_value = image_info['checksum']
else:
message = ('Unable to verify image {} with available checksums. '
'Please make sure the specified \'os_hash_algo\' '
'(currently {}) is supported by this ramdisk, or '
'provide a md5 checksum via the \'checksum\' '
'field'.format(image_info['id'],
image_info.get('os_hash_algo')))
LOG.error(message)
raise errors.RESTError(details=message)
self._expected_hash_value = _fetch_checksum(self._expected_hash_value,
image_info)
@ -370,7 +379,10 @@ def _validate_image_info(ext, image_info=None, **kwargs):
"""
image_info = image_info or {}
for field in ['id', 'urls', 'checksum']:
md5sum_avail = False
os_hash_checksum_avail = False
for field in ['id', 'urls']:
if field not in image_info:
msg = 'Image is missing \'{}\' field.'.format(field)
raise errors.InvalidCommandParamsError(msg)
@ -379,10 +391,12 @@ def _validate_image_info(ext, image_info=None, **kwargs):
raise errors.InvalidCommandParamsError(
'Image \'urls\' must be a list with at least one element.')
if (not isinstance(image_info['checksum'], six.string_types)
or not image_info['checksum']):
raise errors.InvalidCommandParamsError(
'Image \'checksum\' must be a non-empty string.')
if 'checksum' in image_info:
if (not isinstance(image_info['checksum'], six.string_types)
or not image_info['checksum']):
raise errors.InvalidCommandParamsError(
'Image \'checksum\' must be a non-empty string.')
md5sum_avail = True
os_hash_algo = image_info.get('os_hash_algo')
os_hash_value = image_info.get('os_hash_value')
@ -395,6 +409,13 @@ def _validate_image_info(ext, image_info=None, **kwargs):
not os_hash_value):
raise errors.InvalidCommandParamsError(
'Image \'os_hash_value\' must be a non-empty string.')
os_hash_checksum_avail = True
if not (md5sum_avail or os_hash_checksum_avail):
raise errors.InvalidCommandParamsError(
'Image checksum is not available, either the \'checksum\' field '
'or the \'os_hash_algo\' and \'os_hash_value\' fields pair must '
'be set for image verification.')
def _validate_partitioning(device):

View File

@ -72,6 +72,13 @@ class TestStandbyExtension(base.IronicAgentTest):
image_info['os_hash_value'] = 'fake-checksum'
standby._validate_image_info(None, image_info)
def test_validate_image_info_success_without_md5(self):
image_info = _build_fake_image_info()
del image_info['checksum']
image_info['os_hash_algo'] = 'sha512'
image_info['os_hash_value'] = 'fake-checksum'
standby._validate_image_info(None, image_info)
def test_validate_image_info_missing_field(self):
for field in ['id', 'urls', 'checksum']:
invalid_info = _build_fake_image_info()
@ -436,6 +443,24 @@ class TestStandbyExtension(base.IronicAgentTest):
image_download.verify_image(image_location)
hashlib_mock.assert_called_with('sha512')
@mock.patch('hashlib.new', autospec=True)
@mock.patch('six.moves.builtins.open', autospec=True)
@mock.patch('requests.get', autospec=True)
def test_verify_image_success_without_md5(self, requests_mock,
open_mock, hashlib_mock):
image_info = _build_fake_image_info()
del image_info['checksum']
image_info['os_hash_algo'] = 'sha512'
image_info['os_hash_value'] = 'fake-sha512-value'
response = requests_mock.return_value
response.status_code = 200
hexdigest_mock = hashlib_mock.return_value.hexdigest
hexdigest_mock.return_value = image_info['os_hash_value']
image_location = '/foo/bar'
image_download = standby.ImageDownload(image_info)
image_download.verify_image(image_location)
hashlib_mock.assert_called_with('sha512')
@mock.patch('hashlib.md5', autospec=True)
@mock.patch('six.moves.builtins.open', autospec=True)
@mock.patch('requests.get', autospec=True)
@ -487,6 +512,23 @@ class TestStandbyExtension(base.IronicAgentTest):
image_download.verify_image,
image_location)
@mock.patch('hashlib.new', autospec=True)
@mock.patch('six.moves.builtins.open', autospec=True)
@mock.patch('requests.get', autospec=True)
def test_verify_image_failure_without_fallback(self, requests_mock,
open_mock, hashlib_mock):
image_info = _build_fake_image_info()
del image_info['checksum']
image_info['os_hash_algo'] = 'unsupported-algorithm'
image_info['os_hash_value'] = 'fake-value'
response = requests_mock.return_value
response.status_code = 200
self.assertRaisesRegex(errors.RESTError,
'Unable to verify image.*'
'unsupported-algorithm',
standby.ImageDownload,
image_info)
@mock.patch('ironic_lib.disk_utils.get_disk_identifier',
lambda dev: 'ROOT')
@mock.patch('ironic_python_agent.hardware.dispatch_to_managers',

View File

@ -0,0 +1,8 @@
---
fixes:
- |
Fixes an issue that md5 checksum is still required in the image
information when os_hash_algo and os_hash_value are present. The
``checksum`` field is now optional, while ``os_hash_algo`` and
``os_hash_value`` fields must be set if the ``checksum`` field is
not provided.