Treat 'No space left on device' error as fatal
Fail without retries when Errno 28 - "No space left on device" error is encountered. Closes-Bug: #2094854 Change-Id: Ie84b422916ddc02f2474164fe3da083324ef4824
This commit is contained in:
@@ -156,6 +156,11 @@ class ImageDownloadError(RESTError):
|
||||
super(ImageDownloadError, self).__init__(details)
|
||||
|
||||
|
||||
class ImageDownloadOutofSpaceError(ImageDownloadError):
|
||||
"""Raised when an image download fails due to insufficient storage."""
|
||||
pass
|
||||
|
||||
|
||||
class ImageChecksumError(RESTError):
|
||||
"""Error raised when an image fails to verify against its checksum."""
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import errno
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
@@ -679,6 +680,8 @@ def _download_image(image_info):
|
||||
|
||||
:param image_info: Image information dictionary.
|
||||
:raises: ImageDownloadError if the image download fails for any reason.
|
||||
:raises: ImageDownloadOutofSpaceError if the image download fails
|
||||
due to insufficient storage space.
|
||||
:raises: ImageChecksumError if the downloaded image's checksum does not
|
||||
match the one reported in image_info.
|
||||
"""
|
||||
@@ -691,12 +694,24 @@ def _download_image(image_info):
|
||||
with open(image_location, 'wb') as f:
|
||||
try:
|
||||
for chunk in image_download:
|
||||
f.write(chunk)
|
||||
try:
|
||||
f.write(chunk)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOSPC:
|
||||
msg = ('Unable to write image to {}. Error: {}'
|
||||
).format(image_location, str(e))
|
||||
raise errors.ImageDownloadOutofSpaceError(
|
||||
image_info['id'], msg)
|
||||
raise
|
||||
except Exception as e:
|
||||
if isinstance(e, errors.ImageDownloadOutofSpaceError):
|
||||
raise
|
||||
msg = 'Unable to write image to {}. Error: {}'.format(
|
||||
image_location, str(e))
|
||||
raise errors.ImageDownloadError(image_info['id'], msg)
|
||||
image_download.verify_image(image_location)
|
||||
except errors.ImageDownloadOutofSpaceError:
|
||||
raise
|
||||
except (errors.ImageDownloadError,
|
||||
errors.ImageChecksumError) as e:
|
||||
if attempt == CONF.image_download_connection_retries:
|
||||
|
@@ -12,6 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import errno
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
@@ -1775,6 +1776,36 @@ class TestImageDownload(base.IronicAgentTest):
|
||||
sleep_mock.assert_called_with(10)
|
||||
self.assertEqual(2, sleep_mock.call_count)
|
||||
|
||||
@mock.patch('time.sleep', autospec=True)
|
||||
def test_download_image_no_space_error_fatal(self, sleep_mock,
|
||||
requests_mock, hash_mock):
|
||||
content = ['SpongeBob', 'SquarePants']
|
||||
response = requests_mock.return_value
|
||||
response.status_code = 200
|
||||
response.iter_content.return_value = content
|
||||
|
||||
image_info = _build_fake_image_info()
|
||||
hash_mock.return_value.hexdigest.return_value = image_info[
|
||||
'os_hash_value']
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
mock_file = mock_open.return_value.__enter__.return_value
|
||||
mock_file.write.side_effect = OSError(errno.ENOSPC,
|
||||
'No space left on device')
|
||||
|
||||
with mock.patch('builtins.open', mock_open):
|
||||
self.assertRaises(
|
||||
errors.ImageDownloadOutofSpaceError,
|
||||
standby._download_image,
|
||||
image_info
|
||||
)
|
||||
|
||||
requests_mock.assert_called_once_with(image_info['urls'][0],
|
||||
cert=None, verify=True,
|
||||
stream=True, proxies={},
|
||||
timeout=60)
|
||||
sleep_mock.assert_not_called()
|
||||
|
||||
@mock.patch.object(standby.LOG, 'warning', autospec=True)
|
||||
def test_download_image_and_checksum(self, warn_mock, requests_mock,
|
||||
hash_mock):
|
||||
|
@@ -0,0 +1,5 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fail fast when encountering disk space errors during image
|
||||
downloads instead of attempting futile retries.
|
Reference in New Issue
Block a user