def wrapper(self, ctx, attachment_id, *args, **kwargs): try: res = method(self, ctx, attachment_id, *args, **kwargs) except (keystone_exception.NotFound, cinder_exception.NotFound): _reraise(exception.VolumeAttachmentNotFound( attachment_id=attachment_id)) return res
def test_delete_attachment_volume_not_found(self): # Create a server and attach a single volume server = self._create_server(networks='none') server_id = server['id'] self.api.post_server_volume( server_id, {'volumeAttachment': { 'volumeId': self.cinder.IMAGE_BACKED_VOL }}) self._wait_for_volume_attach(server_id, self.cinder.IMAGE_BACKED_VOL) # Assert that we have an active bdm for the attachment before we detach bdm = objects.BlockDeviceMapping.get_by_volume_and_instance( context.get_admin_context(), self.cinder.IMAGE_BACKED_VOL, server_id) with mock.patch('nova.volume.cinder.API.attachment_delete', side_effect=exception.VolumeAttachmentNotFound( attachment_id=bdm.attachment_id)) as ( mock_attachment_delete): # DELETE /servers/{server_id}/os-volume_attachments/{volume_id} is # async but as we are using CastAsCall it's sync in our func tests self.api.delete_server_volume(server_id, self.cinder.IMAGE_BACKED_VOL) mock_attachment_delete.assert_called_once() # Assert that the volume attachment is still removed in Nova self.assertRaises( exception.VolumeBDMNotFound, objects.BlockDeviceMapping.get_by_volume_and_instance, context.get_admin_context(), self.cinder.IMAGE_BACKED_VOL, server_id)
def _find_attachment(attachment_id): """Find attachment corresponding to ``attachment_id``. :returns: A tuple of the volume ID, an attachment dict for the given attachment ID, and a dict (keyed by attachment id) of attachment dicts for the volume. """ for volume_id, attachments in self.volume_to_attachment.items(): for attachment in attachments.values(): if attachment_id == attachment['id']: return volume_id, attachment, attachments raise exception.VolumeAttachmentNotFound( attachment_id=attachment_id)