Check that Glance returns image data before processing it

Now if Glance v2 cannot find image data it returns an empty
response with 204 status code, instead of raising an error.

Glance client handles this situation and wraps the response
with a RequestIdProxy object, whose 'wrapped' attribute is
None.

But when openstack client tries to parse this object using
glanceclient's save_image util function, it fails with
"NoneType object is not iterable" message, for the
object doesn't contain any data.

This patch adds additional check to prevent such behaviour
and raises SystemExit exception if no data was returned from
the server.

Glance v1 is not affected, because it raises an error if can't
find an image data.

Change-Id: I016a60462ba586f9fa7585c2cfafffd7be38de7b
Closes-Bug: #1741223
This commit is contained in:
Mike Fedosin 2018-01-04 17:49:28 +01:00
parent b13a323128
commit ed1b59848f
3 changed files with 64 additions and 0 deletions

View File

@ -17,6 +17,7 @@
import argparse
import logging
import sys
from glanceclient.common import utils as gc_utils
from osc_lib.cli import parseractions
@ -649,6 +650,12 @@ class SaveImage(command.Command):
)
data = image_client.images.data(image.id)
if data.wrapped is None:
msg = _('Image %s has no data.') % image.id
LOG.error(msg)
sys.stdout.write(msg + '\n')
raise SystemExit
gc_utils.save_image(data, parsed_args.file)

View File

@ -15,6 +15,7 @@
import copy
from glanceclient.common import utils as glanceclient_utils
from glanceclient.v2 import schemas
import mock
from osc_lib import exceptions
@ -1505,3 +1506,53 @@ class TestImageUnset(TestImage):
self.image.id, 'test'
)
self.assertIsNone(result)
class TestImageSave(TestImage):
image = image_fakes.FakeImage.create_one_image({})
def setUp(self):
super(TestImageSave, self).setUp()
# Generate a request id
self.resp = mock.MagicMock()
self.resp.headers['x-openstack-request-id'] = 'req_id'
# Get the command object to test
self.cmd = image.SaveImage(self.app, None)
def test_save_data(self):
req_id_proxy = glanceclient_utils.RequestIdProxy(
['some_data', self.resp]
)
self.images_mock.data.return_value = req_id_proxy
arglist = ['--file', '/path/to/file', self.image.id]
verifylist = [
('file', '/path/to/file'),
('image', self.image.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch('glanceclient.common.utils.save_image') as mocked_save:
self.cmd.take_action(parsed_args)
mocked_save.assert_called_once_with(req_id_proxy, '/path/to/file')
def test_save_no_data(self):
req_id_proxy = glanceclient_utils.RequestIdProxy(
[None, self.resp]
)
self.images_mock.data.return_value = req_id_proxy
arglist = ['--file', '/path/to/file', self.image.id]
verifylist = [
('file', '/path/to/file'),
('image', self.image.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Raise SystemExit if no data was provided.
self.assertRaises(SystemExit, self.cmd.take_action, parsed_args)

View File

@ -0,0 +1,6 @@
---
fixes:
- |
'NoneType' object is not iterable when Glance cannot find image data in its
backend.
[Bug `1741223 <https://bugs.launchpad.net/ironic/+bug/1741223>`_]