Catch exception when use invalid architecture of image

Currently, when attempting to rebuild an instance with an image with invalid
architecture, the API raises a 500 error and leaves the instance stuck in
the REBUILDING task state.This patch adds checking image's architecture
before updating instance's task_state. And catches
exception.InvalidArchitectureName then returns HTTPBadRequest.

Change-Id: I25eff0271c856a8d3e83867b448e1dec6f6732ab
Closes-Bug: #1861749
This commit is contained in:
ericxiett 2020-03-05 07:49:38 +08:00
parent 5aa8df8f5c
commit 8dada6d0f6
4 changed files with 50 additions and 0 deletions

View File

@ -1121,6 +1121,7 @@ class ServersController(wsgi.Controller):
exception.ImageNotActive,
exception.ImageUnacceptable,
exception.InvalidMetadata,
exception.InvalidArchitectureName,
) as error:
raise exc.HTTPBadRequest(explanation=error.format_message())
except INVALID_FLAVOR_IMAGE_EXCEPTIONS as error:

View File

@ -3359,6 +3359,12 @@ class API(base.Base):
block_device_info=None,
reboot_type='HARD')
def _check_image_arch(self, image=None):
if image:
img_arch = image.get("properties", {}).get('hw_architecture')
if img_arch:
fields_obj.Architecture.canonicalize(img_arch)
# TODO(stephenfin): We should expand kwargs out to named args
@check_instance_lock
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,
@ -3405,6 +3411,7 @@ class API(base.Base):
image_id, image = self._get_image(context, image_href)
self._check_auto_disk_config(image=image,
auto_disk_config=auto_disk_config)
self._check_image_arch(image=image)
flavor = instance.get_flavor()
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(

View File

@ -658,6 +658,20 @@ class ServerActionsControllerTestV21(test.TestCase):
self.controller._action_rebuild,
self.req, FAKE_UUID, body=body)
@mock.patch.object(compute_api.API, 'rebuild')
def test_rebuild_raise_invalid_architecture_exc(self, mock_rebuild):
body = {
"rebuild": {
"imageRef": self._image_href,
},
}
mock_rebuild.side_effect = exception.InvalidArchitectureName('arm64')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._action_rebuild,
self.req, FAKE_UUID, body=body)
def test_resize_server(self):
body = dict(resize=dict(flavorRef="http://localhost/3"))

View File

@ -3579,6 +3579,19 @@ class _ComputeAPIUnitTestMixIn(object):
lambda obj, context, image_id, **kwargs: self.fake_image)
return self.fake_image['id']
def _setup_fake_image_with_invalid_arch(self):
self.fake_image = {
'id': 2,
'name': 'fake_name',
'status': 'active',
'properties': {"hw_architecture": "arm64"},
}
fake_image.stub_out_image_service(self)
self.stub_out('nova.tests.unit.image.fake._FakeImageService.show',
lambda obj, context, image_id, **kwargs: self.fake_image)
return self.fake_image['id']
@mock.patch('nova.compute.api.API.get_instance_host_status',
new=mock.Mock(return_value=fields_obj.HostStatus.UP))
def test_resize_with_disabled_auto_disk_config_fails(self):
@ -3609,6 +3622,21 @@ class _ComputeAPIUnitTestMixIn(object):
"new password",
auto_disk_config=True)
def test_rebuild_with_invalid_image_arch(self):
instance = fake_instance.fake_instance_obj(
self.context, vm_state=vm_states.ACTIVE, cell_name='fake-cell',
launched_at=timeutils.utcnow(),
system_metadata={}, image_ref='foo',
expected_attrs=['system_metadata'])
image_id = self._setup_fake_image_with_invalid_arch()
self.assertRaises(exception.InvalidArchitectureName,
self.compute_api.rebuild,
self.context,
instance,
image_id,
"new password")
self.assertIsNone(instance.task_state)
@mock.patch.object(objects.RequestSpec, 'get_by_instance_uuid')
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(objects.Instance, 'get_flavor')