Reject boot request for unsupported images

Nova has never supported direct booting of an image of an encrypted
volume uploaded to Glance via the Cinder upload-volume-to-image
process, but instead of rejecting such a request, an 'active' but
unusable instance is created.  This patch allows Nova to use image
metadata to detect such an image and reject the boot request.

Change-Id: Idf84ccff254d26fa13473fe9741ddac21cbcf321
Related-bug: #1852106
Closes-bug: #1863611
(cherry picked from commit 963fd8c0f9)
This commit is contained in:
Brian Rosmaita 2020-02-13 11:09:08 -05:00 committed by Lee Yarwood
parent 6749bad463
commit 240d030902
4 changed files with 52 additions and 0 deletions

View File

@ -736,6 +736,7 @@ class ServersController(wsgi.Controller):
except (exception.ImageNotActive,
exception.ImageBadRequest,
exception.ImageNotAuthorized,
exception.ImageUnacceptable,
exception.FixedIpNotFoundForAddress,
exception.FlavorNotFound,
exception.FlavorDiskTooSmall,

View File

@ -576,6 +576,31 @@ class API(base.Base):
self._validate_flavor_image_nostatus(context, image, instance_type,
root_bdm, validate_numa)
@staticmethod
def _detect_nonbootable_image_from_properties(image_id, image):
"""Check image for a property indicating it's nonbootable.
This is called from the API service to ensure that there are
no known image properties indicating that this image is of a
type that we do not support booting from.
Currently the only such property is 'cinder_encryption_key_id'.
:param image_id: UUID of the image
:param image: a dict representation of the image including properties
:raises: ImageUnacceptable if the image properties indicate
that booting this image is not supported
"""
if not image:
return
image_properties = image.get('properties', {})
if image_properties.get('cinder_encryption_key_id'):
reason = _('Direct booting of an image uploaded from an '
'encrypted volume is unsupported.')
raise exception.ImageUnacceptable(image_id=image_id,
reason=reason)
@staticmethod
def _validate_flavor_image_nostatus(context, image, instance_type,
root_bdm, validate_numa=True,
@ -876,6 +901,7 @@ class API(base.Base):
validate_numa=True):
self._check_metadata_properties_quota(context, metadata)
self._check_injected_file_quota(context, files_to_inject)
self._detect_nonbootable_image_from_properties(image_id, image)
self._validate_flavor_image(context, image_id, image,
instance_type, root_bdm,
validate_numa=validate_numa)

View File

@ -4317,6 +4317,22 @@ class ServersControllerCreateTest(test.TestCase):
"Flavor's disk is too small for requested image."):
self.controller.create(self.req, body=self.body)
@mock.patch.object(fake._FakeImageService, 'show',
return_value=dict(
id='76fa36fc-c930-4bf3-8c8a-ea2a2420deb6',
status='active',
properties=dict(
cinder_encryption_key_id=fakes.FAKE_UUID)))
def test_create_server_image_nonbootable(self, mock_show):
self.req.body = jsonutils.dump_as_bytes(self.body)
expected_msg = ("Image {} is unacceptable: Direct booting of an image "
"uploaded from an encrypted volume is unsupported.")
with testtools.ExpectedException(
webob.exc.HTTPBadRequest,
expected_msg.format(self.image_uuid)):
self.controller.create(self.req, body=self.body)
def test_create_instance_with_image_non_uuid(self):
self.body['server']['imageRef'] = 'not-uuid'
self.assertRaises(exception.ValidationError,

View File

@ -0,0 +1,9 @@
---
fixes:
- |
The Compute service has never supported direct booting of an instance from
an image that was created by the Block Storage service from an encrypted
volume. Previously, this operation would result in an ACTIVE instance that
was unusable. Beginning with this release, an attempt to boot from such an
image will result in the Compute API returning a 400 (Bad Request)
response.