summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Rosmaita <rosmaita.fossdev@gmail.com>2020-02-13 11:09:08 -0500
committerElod Illes <elod.illes@est.tech>2020-07-17 14:03:31 +0200
commit418b9450e4b9bab15a4a0f92d013e53d18de3342 (patch)
treec2b16850a9b811b8ff8a8aeb7cc16f74056e885a
parent8290f746d85918fffbfefbdb50de72e52bec2ada (diff)
downloadnova-418b9450e4b9bab15a4a0f92d013e53d18de3342.tar.gz
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 963fd8c0f956bdf5c6c8987aa5d9f836386fd5ed) (cherry picked from commit 240d0309023fcaf20df44f819e9b3e14af97f526) (cherry picked from commit 6e71909b0b8ad8d20d0863e714cad2a7b120f658) (cherry picked from commit 02551d6d6a3baee49309cffbc3bef2508fcafe72)
-rw-r--r--nova/api/openstack/compute/servers.py1
-rw-r--r--nova/compute/api.py26
-rw-r--r--nova/tests/unit/api/openstack/compute/test_serversV21.py16
-rw-r--r--releasenotes/notes/cinder-detect-nonbootable-image-6fad7f865b45f879.yaml9
4 files changed, 52 insertions, 0 deletions
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index b056999a4c..f7130669fe 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -582,6 +582,7 @@ class ServersController(wsgi.Controller):
exception.ImageNotActive,
exception.ImageBadRequest,
exception.ImageNotAuthorized,
+ exception.ImageUnacceptable,
exception.FixedIpNotFoundForAddress,
exception.FlavorNotFound,
exception.FlavorDiskTooSmall,
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 6bd6a78cd0..6f1ff7c48e 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -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,
diff --git a/nova/tests/unit/api/openstack/compute/test_serversV21.py b/nova/tests/unit/api/openstack/compute/test_serversV21.py
index 473188c70a..a76fdc3898 100644
--- a/nova/tests/unit/api/openstack/compute/test_serversV21.py
+++ b/nova/tests/unit/api/openstack/compute/test_serversV21.py
@@ -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,
diff --git a/releasenotes/notes/cinder-detect-nonbootable-image-6fad7f865b45f879.yaml b/releasenotes/notes/cinder-detect-nonbootable-image-6fad7f865b45f879.yaml
new file mode 100644
index 0000000000..0746df58f2
--- /dev/null
+++ b/releasenotes/notes/cinder-detect-nonbootable-image-6fad7f865b45f879.yaml
@@ -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.