Do not recalculate checksum if disk_format is not changed
Even if a glance image is raw, we still recalculate the checksum after "converting" it to raw. This process may take exceptionally long. Change-Id: Id93d518b8d2b8064ff901f1a0452abd825e366c0
This commit is contained in:
parent
17d97d51ad
commit
f00da959ea
@ -15,6 +15,19 @@ provisioned within a short period of time.
|
|||||||
the ``noop`` networking. The case where inspection, cleaning and
|
the ``noop`` networking. The case where inspection, cleaning and
|
||||||
provisioning networks are different is not supported.
|
provisioning networks are different is not supported.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Fast track mode is very sensitive to long-running processes on the conductor
|
||||||
|
side that may prevent agent heartbeats from being registered.
|
||||||
|
|
||||||
|
For example, converting a large image to the raw format may take long enough
|
||||||
|
to reach the fast track timeout. In this case, you can either :ref:`use raw
|
||||||
|
images <stream_raw_images>` or move the conversion to the agent side with:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
force_raw_images = False
|
||||||
|
|
||||||
Enabling
|
Enabling
|
||||||
========
|
========
|
||||||
|
|
||||||
|
@ -81,6 +81,46 @@ accessible from HTTP service. Please refer to configuration option
|
|||||||
``FollowSymLinks`` if you are using Apache HTTP server, or
|
``FollowSymLinks`` if you are using Apache HTTP server, or
|
||||||
``disable_symlinks`` if Nginx HTTP server is in use.
|
``disable_symlinks`` if Nginx HTTP server is in use.
|
||||||
|
|
||||||
|
.. _stream_raw_images:
|
||||||
|
|
||||||
|
Streaming raw images
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The Bare Metal service is capable of streaming raw images directly to the
|
||||||
|
target disk of a node, without caching them in the node's RAM. When the source
|
||||||
|
image is not already raw, the conductor will convert the image and calculate
|
||||||
|
the new checksum.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
If no algorithm is specified via the ``image_os_hash_algo`` field, or if
|
||||||
|
this field is set to ``md5``, SHA256 is used for the updated checksum.
|
||||||
|
|
||||||
|
For HTTP or local file images that are already raw, you need to explicitly set
|
||||||
|
the disk format to prevent the checksum from being unnecessarily re-calculated.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
baremetal node set <node> \
|
||||||
|
--instance-info image_source=http://server/myimage.img \
|
||||||
|
--instance-info image_os_hash_algo=sha512 \
|
||||||
|
--instance-info image_os_hash_value=<SHA512 of the raw image> \
|
||||||
|
--instance-info image_disk_format=raw
|
||||||
|
|
||||||
|
To disable this feature and cache images in the node's RAM, set
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[agent]
|
||||||
|
stream_raw_images = False
|
||||||
|
|
||||||
|
To disable the conductor-side conversion completely, set
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
force_raw_images = False
|
||||||
|
|
||||||
.. _ansible-deploy:
|
.. _ansible-deploy:
|
||||||
|
|
||||||
Ansible deploy
|
Ansible deploy
|
||||||
|
@ -277,9 +277,8 @@ the space requirements are different:
|
|||||||
In both cases a cached image is converted to raw if ``force_raw_images``
|
In both cases a cached image is converted to raw if ``force_raw_images``
|
||||||
is ``True`` (the default).
|
is ``True`` (the default).
|
||||||
|
|
||||||
.. note::
|
See :ref:`image_download_source` and :ref:`stream_raw_images` for more
|
||||||
``image_download_source`` can also be provided in the node's
|
details.
|
||||||
``driver_info`` or ``instance_info``. See :ref:`image_download_source`.
|
|
||||||
|
|
||||||
* When network boot is used, the instance image kernel and ramdisk are cached
|
* When network boot is used, the instance image kernel and ramdisk are cached
|
||||||
locally while the instance is active.
|
locally while the instance is active.
|
||||||
|
@ -1093,6 +1093,11 @@ def _cache_and_convert_image(task, instance_info, image_info=None):
|
|||||||
_, image_path = cache_instance_image(task.context, task.node,
|
_, image_path = cache_instance_image(task.context, task.node,
|
||||||
force_raw=force_raw)
|
force_raw=force_raw)
|
||||||
if force_raw or image_info is None:
|
if force_raw or image_info is None:
|
||||||
|
if image_info is None:
|
||||||
|
initial_format = instance_info.get('image_disk_format')
|
||||||
|
else:
|
||||||
|
initial_format = image_info.get('disk_format')
|
||||||
|
|
||||||
if force_raw:
|
if force_raw:
|
||||||
instance_info['image_disk_format'] = 'raw'
|
instance_info['image_disk_format'] = 'raw'
|
||||||
else:
|
else:
|
||||||
@ -1108,12 +1113,17 @@ def _cache_and_convert_image(task, instance_info, image_info=None):
|
|||||||
# sha256.
|
# sha256.
|
||||||
if image_info is None:
|
if image_info is None:
|
||||||
os_hash_algo = instance_info.get('image_os_hash_algo')
|
os_hash_algo = instance_info.get('image_os_hash_algo')
|
||||||
|
hash_value = instance_info.get('image_os_hash_value')
|
||||||
|
old_checksum = instance_info.get('image_checksum')
|
||||||
else:
|
else:
|
||||||
os_hash_algo = image_info.get('os_hash_algo')
|
os_hash_algo = image_info.get('os_hash_algo')
|
||||||
|
hash_value = image_info.get('os_hash_value')
|
||||||
|
old_checksum = image_info.get('checksum')
|
||||||
|
|
||||||
|
if initial_format != instance_info['image_disk_format']:
|
||||||
if not os_hash_algo or os_hash_algo == 'md5':
|
if not os_hash_algo or os_hash_algo == 'md5':
|
||||||
LOG.debug("Checksum algorithm for image %(image)s for node "
|
LOG.debug("Checksum algorithm for image %(image)s for node "
|
||||||
"%(node)s is set to '%(algo)s', changing to 'sha256'",
|
"%(node)s is set to '%(algo)s', changing to sha256",
|
||||||
{'algo': os_hash_algo, 'node': task.node.uuid,
|
{'algo': os_hash_algo, 'node': task.node.uuid,
|
||||||
'image': image_path})
|
'image': image_path})
|
||||||
os_hash_algo = 'sha256'
|
os_hash_algo = 'sha256'
|
||||||
@ -1123,6 +1133,9 @@ def _cache_and_convert_image(task, instance_info, image_info=None):
|
|||||||
{'image': image_path, 'node': task.node.uuid})
|
{'image': image_path, 'node': task.node.uuid})
|
||||||
instance_info['image_checksum'] = None
|
instance_info['image_checksum'] = None
|
||||||
hash_value = compute_image_checksum(image_path, os_hash_algo)
|
hash_value = compute_image_checksum(image_path, os_hash_algo)
|
||||||
|
else:
|
||||||
|
instance_info['image_checksum'] = old_checksum
|
||||||
|
|
||||||
instance_info['image_os_hash_algo'] = os_hash_algo
|
instance_info['image_os_hash_algo'] = os_hash_algo
|
||||||
instance_info['image_os_hash_value'] = hash_value
|
instance_info['image_os_hash_value'] = hash_value
|
||||||
else:
|
else:
|
||||||
|
@ -1940,7 +1940,7 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
self.node.save()
|
self.node.save()
|
||||||
|
|
||||||
self.checksum_mock = self.useFixture(fixtures.MockPatchObject(
|
self.checksum_mock = self.useFixture(fixtures.MockPatchObject(
|
||||||
fileutils, 'compute_file_checksum')).mock
|
fileutils, 'compute_file_checksum', autospec=True)).mock
|
||||||
self.checksum_mock.return_value = 'fake-checksum'
|
self.checksum_mock.return_value = 'fake-checksum'
|
||||||
self.cache_image_mock = self.useFixture(fixtures.MockPatchObject(
|
self.cache_image_mock = self.useFixture(fixtures.MockPatchObject(
|
||||||
utils, 'cache_instance_image', autospec=True)).mock
|
utils, 'cache_instance_image', autospec=True)).mock
|
||||||
@ -2012,9 +2012,25 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
image_info=self.image_info, expect_raw=True)
|
image_info=self.image_info, expect_raw=True)
|
||||||
|
|
||||||
self.assertIsNone(instance_info['image_checksum'])
|
self.assertIsNone(instance_info['image_checksum'])
|
||||||
|
self.assertEqual(instance_info['image_os_hash_algo'], 'sha512')
|
||||||
|
self.assertEqual(instance_info['image_os_hash_value'],
|
||||||
|
'fake-checksum')
|
||||||
self.assertEqual(instance_info['image_disk_format'], 'raw')
|
self.assertEqual(instance_info['image_disk_format'], 'raw')
|
||||||
calls = [mock.call(image_path, algorithm='sha512')]
|
self.checksum_mock.assert_called_once_with(image_path,
|
||||||
self.checksum_mock.assert_has_calls(calls)
|
algorithm='sha512')
|
||||||
|
|
||||||
|
def test_build_instance_info_already_raw(self):
|
||||||
|
cfg.CONF.set_override('force_raw_images', True)
|
||||||
|
self.image_info['disk_format'] = 'raw'
|
||||||
|
image_path, instance_info = self._test_build_instance_info(
|
||||||
|
image_info=self.image_info, expect_raw=True)
|
||||||
|
|
||||||
|
self.assertEqual(instance_info['image_checksum'], 'aa')
|
||||||
|
self.assertEqual(instance_info['image_os_hash_algo'], 'sha512')
|
||||||
|
self.assertEqual(instance_info['image_os_hash_value'],
|
||||||
|
'fake-sha512')
|
||||||
|
self.assertEqual(instance_info['image_disk_format'], 'raw')
|
||||||
|
self.checksum_mock.assert_not_called()
|
||||||
|
|
||||||
def test_build_instance_info_force_raw_drops_md5(self):
|
def test_build_instance_info_force_raw_drops_md5(self):
|
||||||
cfg.CONF.set_override('force_raw_images', True)
|
cfg.CONF.set_override('force_raw_images', True)
|
||||||
@ -2027,6 +2043,17 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
calls = [mock.call(image_path, algorithm='sha256')]
|
calls = [mock.call(image_path, algorithm='sha256')]
|
||||||
self.checksum_mock.assert_has_calls(calls)
|
self.checksum_mock.assert_has_calls(calls)
|
||||||
|
|
||||||
|
def test_build_instance_info_already_raw_keeps_md5(self):
|
||||||
|
cfg.CONF.set_override('force_raw_images', True)
|
||||||
|
self.image_info['os_hash_algo'] = 'md5'
|
||||||
|
self.image_info['disk_format'] = 'raw'
|
||||||
|
image_path, instance_info = self._test_build_instance_info(
|
||||||
|
image_info=self.image_info, expect_raw=True)
|
||||||
|
|
||||||
|
self.assertEqual(instance_info['image_checksum'], 'aa')
|
||||||
|
self.assertEqual(instance_info['image_disk_format'], 'raw')
|
||||||
|
self.checksum_mock.assert_not_called()
|
||||||
|
|
||||||
@mock.patch.object(image_service.HttpImageService, 'validate_href',
|
@mock.patch.object(image_service.HttpImageService, 'validate_href',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
def test_build_instance_info_file_image(self, validate_href_mock):
|
def test_build_instance_info_file_image(self, validate_href_mock):
|
||||||
@ -2035,7 +2062,6 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
i_info['image_source'] = 'file://image-ref'
|
i_info['image_source'] = 'file://image-ref'
|
||||||
i_info['image_checksum'] = 'aa'
|
i_info['image_checksum'] = 'aa'
|
||||||
i_info['root_gb'] = 10
|
i_info['root_gb'] = 10
|
||||||
i_info['image_checksum'] = 'aa'
|
|
||||||
driver_internal_info['is_whole_disk_image'] = True
|
driver_internal_info['is_whole_disk_image'] = True
|
||||||
self.node.instance_info = i_info
|
self.node.instance_info = i_info
|
||||||
self.node.driver_internal_info = driver_internal_info
|
self.node.driver_internal_info = driver_internal_info
|
||||||
@ -2052,6 +2078,7 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
self.assertEqual(expected_url, info['image_url'])
|
self.assertEqual(expected_url, info['image_url'])
|
||||||
self.assertEqual('sha256', info['image_os_hash_algo'])
|
self.assertEqual('sha256', info['image_os_hash_algo'])
|
||||||
self.assertEqual('fake-checksum', info['image_os_hash_value'])
|
self.assertEqual('fake-checksum', info['image_os_hash_value'])
|
||||||
|
self.assertEqual('raw', info['image_disk_format'])
|
||||||
self.cache_image_mock.assert_called_once_with(
|
self.cache_image_mock.assert_called_once_with(
|
||||||
task.context, task.node, force_raw=True)
|
task.context, task.node, force_raw=True)
|
||||||
self.checksum_mock.assert_called_once_with(
|
self.checksum_mock.assert_called_once_with(
|
||||||
@ -2068,7 +2095,6 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
i_info['image_source'] = 'http://image-ref'
|
i_info['image_source'] = 'http://image-ref'
|
||||||
i_info['image_checksum'] = 'aa'
|
i_info['image_checksum'] = 'aa'
|
||||||
i_info['root_gb'] = 10
|
i_info['root_gb'] = 10
|
||||||
i_info['image_checksum'] = 'aa'
|
|
||||||
driver_internal_info['is_whole_disk_image'] = True
|
driver_internal_info['is_whole_disk_image'] = True
|
||||||
self.node.instance_info = i_info
|
self.node.instance_info = i_info
|
||||||
self.node.driver_internal_info = driver_internal_info
|
self.node.driver_internal_info = driver_internal_info
|
||||||
@ -2102,7 +2128,6 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
i_info['image_source'] = 'http://image-ref'
|
i_info['image_source'] = 'http://image-ref'
|
||||||
i_info['image_checksum'] = 'aa'
|
i_info['image_checksum'] = 'aa'
|
||||||
i_info['root_gb'] = 10
|
i_info['root_gb'] = 10
|
||||||
i_info['image_checksum'] = 'aa'
|
|
||||||
i_info['image_download_source'] = 'local'
|
i_info['image_download_source'] = 'local'
|
||||||
driver_internal_info['is_whole_disk_image'] = True
|
driver_internal_info['is_whole_disk_image'] = True
|
||||||
self.node.instance_info = i_info
|
self.node.instance_info = i_info
|
||||||
@ -2138,7 +2163,6 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
i_info['image_source'] = 'http://image-ref'
|
i_info['image_source'] = 'http://image-ref'
|
||||||
i_info['image_checksum'] = 'aa'
|
i_info['image_checksum'] = 'aa'
|
||||||
i_info['root_gb'] = 10
|
i_info['root_gb'] = 10
|
||||||
i_info['image_checksum'] = 'aa'
|
|
||||||
d_info['image_download_source'] = 'local'
|
d_info['image_download_source'] = 'local'
|
||||||
driver_internal_info['is_whole_disk_image'] = True
|
driver_internal_info['is_whole_disk_image'] = True
|
||||||
self.node.instance_info = i_info
|
self.node.instance_info = i_info
|
||||||
@ -2164,6 +2188,41 @@ class TestBuildInstanceInfoForHttpProvisioning(db_base.DbTestCase):
|
|||||||
validate_href_mock.assert_called_once_with(
|
validate_href_mock.assert_called_once_with(
|
||||||
mock.ANY, expected_url, False)
|
mock.ANY, expected_url, False)
|
||||||
|
|
||||||
|
@mock.patch.object(image_service.HttpImageService, 'validate_href',
|
||||||
|
autospec=True)
|
||||||
|
def test_build_instance_info_local_image_already_raw(self,
|
||||||
|
validate_href_mock):
|
||||||
|
cfg.CONF.set_override('image_download_source', 'local', group='agent')
|
||||||
|
i_info = self.node.instance_info
|
||||||
|
driver_internal_info = self.node.driver_internal_info
|
||||||
|
i_info['image_source'] = 'http://image-ref'
|
||||||
|
i_info['image_checksum'] = 'aa'
|
||||||
|
i_info['root_gb'] = 10
|
||||||
|
i_info['image_disk_format'] = 'raw'
|
||||||
|
driver_internal_info['is_whole_disk_image'] = True
|
||||||
|
self.node.instance_info = i_info
|
||||||
|
self.node.driver_internal_info = driver_internal_info
|
||||||
|
self.node.save()
|
||||||
|
|
||||||
|
expected_url = (
|
||||||
|
'http://172.172.24.10:8080/agent_images/%s' % self.node.uuid)
|
||||||
|
|
||||||
|
with task_manager.acquire(
|
||||||
|
self.context, self.node.uuid, shared=False) as task:
|
||||||
|
|
||||||
|
info = utils.build_instance_info_for_deploy(task)
|
||||||
|
|
||||||
|
self.assertEqual(expected_url, info['image_url'])
|
||||||
|
self.assertEqual('aa', info['image_checksum'])
|
||||||
|
self.assertEqual('raw', info['image_disk_format'])
|
||||||
|
self.assertIsNone(info['image_os_hash_algo'])
|
||||||
|
self.assertIsNone(info['image_os_hash_value'])
|
||||||
|
self.cache_image_mock.assert_called_once_with(
|
||||||
|
task.context, task.node, force_raw=True)
|
||||||
|
self.checksum_mock.assert_not_called()
|
||||||
|
validate_href_mock.assert_called_once_with(
|
||||||
|
mock.ANY, expected_url, False)
|
||||||
|
|
||||||
|
|
||||||
class TestStorageInterfaceUtils(db_base.DbTestCase):
|
class TestStorageInterfaceUtils(db_base.DbTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
5
releasenotes/notes/no-recalculate-653e524fd6160e72.yaml
Normal file
5
releasenotes/notes/no-recalculate-653e524fd6160e72.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
No longer re-calculates checksums for images that are already raw.
|
||||||
|
Previously, it would cause significant delays in deploying raw images.
|
Loading…
Reference in New Issue
Block a user