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)
(cherry picked from commit 240d030902)
(cherry picked from commit 6e71909b0b)
(cherry picked from commit 02551d6d6a)
This commit is contained in:
Brian Rosmaita 2020-02-13 11:09:08 -05:00 committed by Elod Illes
parent 8290f746d8
commit 418b9450e4
4 changed files with 52 additions and 0 deletions

View File

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

View File

@ -557,6 +557,31 @@ class API(base.Base):
# reason, we rely on the DB to cast True to a String.
return True if bool_val else ''
@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)
def _check_requested_image(self, context, image_id, image,
instance_type, root_bdm):
if not image:
@ -773,6 +798,7 @@ class API(base.Base):
self._check_injected_file_quota(context, files_to_inject)
self._check_requested_image(context, image_id, image,
instance_type, root_bdm)
self._detect_nonbootable_image_from_properties(image_id, image)
def _validate_and_build_base_options(self, context, instance_type,
boot_meta, image_href, image_id,

View File

@ -3050,6 +3050,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.