diff --git a/cinder/api/v3/attachments.py b/cinder/api/v3/attachments.py index caa005c518e..6c457920f9b 100644 --- a/cinder/api/v3/attachments.py +++ b/cinder/api/v3/attachments.py @@ -170,7 +170,8 @@ class AttachmentsController(wsgi.Controller): volume_ref, instance_uuid, connector=connector)) - except exception.NotAuthorized: + except (exception.NotAuthorized, + exception.InvalidVolume): raise except exception.CinderException as ex: err_msg = _( diff --git a/cinder/tests/unit/api/v3/test_attachments.py b/cinder/tests/unit/api/v3/test_attachments.py index a1f50aee2a6..8d38e1c56ce 100644 --- a/cinder/tests/unit/api/v3/test_attachments.py +++ b/cinder/tests/unit/api/v3/test_attachments.py @@ -244,6 +244,30 @@ class AttachmentsAPITestCase(test.TestCase): self.assertRaises(exception.ValidationError, self.controller.create, req, body=fake_body) + @mock.patch('cinder.volume.api.API._attachment_reserve') + def test_create_attachment_in_use_volume_multiattach_false(self, + mock_reserve): + """Negative test for creating an attachment on an in-use volume.""" + req = fakes.HTTPRequest.blank('/v3/%s/attachments' % + fake.PROJECT_ID, + version=mv.NEW_ATTACH) + body = { + "attachment": + { + "connector": None, + "instance_uuid": fake.UUID1, + "volume_uuid": self.volume1.id + }, + } + mock_reserve.side_effect = ( + exception.InvalidVolume( + reason="Volume %s status must be available or " + "downloading" % self.volume1.id)) + # Note that if we were using the full WSGi stack, the + # ResourceExceptionHandler would convert this to an HTTPBadRequest. + self.assertRaises(exception.InvalidVolume, + self.controller.create, req, body=body) + @ddt.data(False, True) def test_list_attachments(self, is_detail): url = '/v3/%s/attachments' % fake.PROJECT_ID