diff --git a/ironic/common/utils.py b/ironic/common/utils.py index fdb4ae48c2..3fb4646ba6 100644 --- a/ironic/common/utils.py +++ b/ironic/common/utils.py @@ -31,6 +31,7 @@ import jinja2 from oslo_concurrency import processutils from oslo_log import log as logging from oslo_serialization import jsonutils +from oslo_utils import fileutils from oslo_utils import netutils from oslo_utils import timeutils import pytz @@ -229,28 +230,6 @@ def _get_hash_object(hash_algo_name): return getattr(hashlib, hash_algo_name)() -def hash_file(file_like_object, hash_algo='md5'): - """Generate a hash for the contents of a file. - - It returns a hash of the file object as a string of double length, - containing only hexadecimal digits. It supports all the algorithms - hashlib does. - :param file_like_object: file like object whose hash to be calculated. - :param hash_algo: name of the hashing strategy, default being 'md5'. - :raises: InvalidParameterValue, on unsupported or invalid input. - :returns: a condensed digest of the bytes of contents. - """ - checksum = _get_hash_object(hash_algo) - while True: - chunk = file_like_object.read(32768) - if not chunk: - break - encoded_chunk = (chunk.encode(encoding='utf-8') - if isinstance(chunk, six.string_types) else chunk) - checksum.update(encoded_chunk) - return checksum.hexdigest() - - def file_has_content(path, content, hash_algo='md5'): """Checks that content of the file is the same as provided reference. @@ -260,8 +239,7 @@ def file_has_content(path, content, hash_algo='md5'): :returns: True if the hash of reference content is the same as the hash of file's content, False otherwise """ - with open(path, 'rb') as existing: - file_hash_hex = hash_file(existing, hash_algo=hash_algo) + file_hash_hex = fileutils.compute_file_checksum(path, algorithm=hash_algo) ref_hash = _get_hash_object(hash_algo) encoded_content = (content.encode(encoding='utf-8') if isinstance(content, six.string_types) else content) diff --git a/ironic/drivers/modules/ilo/common.py b/ironic/drivers/modules/ilo/common.py index d528c20c49..55eb7cde61 100644 --- a/ironic/drivers/modules/ilo/common.py +++ b/ironic/drivers/modules/ilo/common.py @@ -22,6 +22,7 @@ import tempfile from ironic_lib import utils as ironic_utils from oslo_log import log as logging +from oslo_utils import fileutils from oslo_utils import importutils import six import six.moves.urllib.parse as urlparse @@ -775,8 +776,8 @@ def verify_image_checksum(image_location, expected_checksum): verification fails. """ try: - with open(image_location, 'rb') as fd: - actual_checksum = utils.hash_file(fd) + actual_checksum = fileutils.compute_file_checksum(image_location, + algorithm='md5') except IOError as e: LOG.error("Error opening file: %(file)s", {'file': image_location}) raise exception.ImageRefValidationFailed(image_href=image_location, diff --git a/ironic/tests/unit/common/test_utils.py b/ironic/tests/unit/common/test_utils.py index 36af63ed2c..8d7b21aed0 100644 --- a/ironic/tests/unit/common/test_utils.py +++ b/ironic/tests/unit/common/test_utils.py @@ -15,7 +15,6 @@ import datetime import errno -import hashlib import os import os.path import shutil @@ -26,7 +25,6 @@ import mock from oslo_concurrency import processutils from oslo_config import cfg from oslo_utils import netutils -import six from ironic.common import exception from ironic.common import utils @@ -117,66 +115,19 @@ class GenericUtilsTestCase(base.TestCase): utils._get_hash_object, 'hickory-dickory-dock') - def test_hash_file_for_md5(self): - # | GIVEN | - data = b'Mary had a little lamb, its fleece as white as snow' - file_like_object = six.BytesIO(data) - expected = hashlib.md5(data).hexdigest() - # | WHEN | - actual = utils.hash_file(file_like_object) # using default, 'md5' - # | THEN | - self.assertEqual(expected, actual) - - def test_hash_file_for_md5_not_binary(self): - # | GIVEN | - data = u'Mary had a little lamb, its fleece as white as sno\u0449' - file_like_object = six.StringIO(data) - expected = hashlib.md5(data.encode('utf-8')).hexdigest() - # | WHEN | - actual = utils.hash_file(file_like_object) # using default, 'md5' - # | THEN | - self.assertEqual(expected, actual) - - def test_hash_file_for_sha1(self): - # | GIVEN | - data = b'Mary had a little lamb, its fleece as white as snow' - file_like_object = six.BytesIO(data) - expected = hashlib.sha1(data).hexdigest() - # | WHEN | - actual = utils.hash_file(file_like_object, 'sha1') - # | THEN | - self.assertEqual(expected, actual) - - def test_hash_file_for_sha512(self): - # | GIVEN | - data = b'Mary had a little lamb, its fleece as white as snow' - file_like_object = six.BytesIO(data) - expected = hashlib.sha512(data).hexdigest() - # | WHEN | - actual = utils.hash_file(file_like_object, 'sha512') - # | THEN | - self.assertEqual(expected, actual) - - def test_hash_file_throws_for_invalid_or_unsupported_hash(self): - # | GIVEN | - data = b'Mary had a little lamb, its fleece as white as snow' - file_like_object = six.BytesIO(data) - # | WHEN | & | THEN | - self.assertRaises(exception.InvalidParameterValue, utils.hash_file, - file_like_object, 'hickory-dickory-dock') - def test_file_has_content_equal(self): data = b'Mary had a little lamb, its fleece as white as snow' ref = data - with mock.patch('ironic.common.utils.open', + with mock.patch('oslo_utils.fileutils.open', mock.mock_open(read_data=data)) as mopen: self.assertTrue(utils.file_has_content('foo', ref)) mopen.assert_called_once_with('foo', 'rb') def test_file_has_content_equal_not_binary(self): - data = u'Mary had a little lamb, its fleece as white as sno\u0449' + data = ('Mary had a little lamb, its fleece as white as ' + 'sno\u0449').encode('utf-8') ref = data - with mock.patch('ironic.common.utils.open', + with mock.patch('oslo_utils.fileutils.open', mock.mock_open(read_data=data)) as mopen: self.assertTrue(utils.file_has_content('foo', ref)) mopen.assert_called_once_with('foo', 'rb') @@ -184,7 +135,7 @@ class GenericUtilsTestCase(base.TestCase): def test_file_has_content_differ(self): data = b'Mary had a little lamb, its fleece as white as snow' ref = data + b'!' - with mock.patch('ironic.common.utils.open', + with mock.patch('oslo_utils.fileutils.open', mock.mock_open(read_data=data)) as mopen: self.assertFalse(utils.file_has_content('foo', ref)) mopen.assert_called_once_with('foo', 'rb')