Merge "Remove useless volume when boot from volume failed"
This commit is contained in:
commit
4db0c9224d
|
@ -1386,15 +1386,18 @@ class ComputeManager(manager.Manager):
|
|||
volume = self.volume_api.get(context, vol_id)
|
||||
volume_status = volume['status']
|
||||
if volume_status not in ['creating', 'downloading']:
|
||||
if volume_status != 'available':
|
||||
LOG.warning(_LW("Volume id: %s finished being created but "
|
||||
"was not set as 'available'"), vol_id)
|
||||
return attempt
|
||||
if volume_status == 'available':
|
||||
return attempt
|
||||
LOG.warning(_LW("Volume id: %(vol_id)s finished being "
|
||||
"created but its status is %(vol_status)s."),
|
||||
{'vol_id': vol_id,
|
||||
'vol_status': volume_status})
|
||||
break
|
||||
greenthread.sleep(CONF.block_device_allocate_retries_interval)
|
||||
# NOTE(harlowja): Should only happen if we ran out of attempts
|
||||
raise exception.VolumeNotCreated(volume_id=vol_id,
|
||||
seconds=int(time.time() - start),
|
||||
attempts=attempts)
|
||||
attempts=attempt,
|
||||
volume_status=volume_status)
|
||||
|
||||
def _decode_files(self, injected_files):
|
||||
"""Base64 decode the list of files to inject."""
|
||||
|
|
|
@ -275,7 +275,7 @@ class VolumeUnattached(Invalid):
|
|||
class VolumeNotCreated(NovaException):
|
||||
msg_fmt = _("Volume %(volume_id)s did not finish being created"
|
||||
" even after we waited %(seconds)s seconds or %(attempts)s"
|
||||
" attempts.")
|
||||
" attempts. And its status is %(volume_status)s.")
|
||||
|
||||
|
||||
class InvalidKeypair(Invalid):
|
||||
|
|
|
@ -452,6 +452,17 @@ class ComputeVolumeTestCase(BaseTestCase):
|
|||
self.compute._await_block_device_map_created,
|
||||
self.context, '1')
|
||||
|
||||
def test_await_block_device_created_failed(self):
|
||||
c = self.compute
|
||||
|
||||
fake_result = {'status': 'error', 'id': 'blah'}
|
||||
with mock.patch.object(c.volume_api, 'get',
|
||||
return_value=fake_result) as fake_get:
|
||||
self.assertRaises(exception.VolumeNotCreated,
|
||||
c._await_block_device_map_created,
|
||||
self.context, '1')
|
||||
fake_get.assert_called_once_with(self.context, '1')
|
||||
|
||||
def test_await_block_device_created_slow(self):
|
||||
c = self.compute
|
||||
self.flags(block_device_allocate_retries=4)
|
||||
|
|
|
@ -20,6 +20,7 @@ import six
|
|||
|
||||
from nova import block_device
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit import matchers
|
||||
|
@ -328,6 +329,37 @@ class TestDriverBlockDevice(test.NoDBTestCase):
|
|||
self.assertEqual('fake-volume-id-2', test_bdm.volume_id)
|
||||
self.assertEqual(3, test_bdm.volume_size)
|
||||
|
||||
def _test_call_wait_func(self, delete_on_termination, delete_fail=False):
|
||||
test_bdm = self.driver_classes['volume'](self.volume_bdm)
|
||||
test_bdm['delete_on_termination'] = delete_on_termination
|
||||
with mock.patch.object(self.volume_api, 'delete') as vol_delete:
|
||||
wait_func = mock.MagicMock()
|
||||
mock_exception = exception.VolumeNotCreated(volume_id='fake-id',
|
||||
seconds=1,
|
||||
attempts=1,
|
||||
volume_status='error')
|
||||
wait_func.side_effect = mock_exception
|
||||
|
||||
if delete_on_termination and delete_fail:
|
||||
vol_delete.side_effect = Exception()
|
||||
|
||||
self.assertRaises(exception.VolumeNotCreated,
|
||||
test_bdm._call_wait_func,
|
||||
context=self.context,
|
||||
wait_func=wait_func,
|
||||
volume_api=self.volume_api,
|
||||
volume_id='fake-id')
|
||||
self.assertEqual(delete_on_termination, vol_delete.called)
|
||||
|
||||
def test_call_wait_delete_volume(self):
|
||||
self._test_call_wait_func(True)
|
||||
|
||||
def test_call_wait_delete_volume_fail(self):
|
||||
self._test_call_wait_func(True, True)
|
||||
|
||||
def test_call_wait_no_delete_volume(self):
|
||||
self._test_call_wait_func(False)
|
||||
|
||||
def _test_volume_attach(self, driver_bdm, bdm_dict,
|
||||
fake_volume, check_attach=True,
|
||||
fail_check_attach=False, driver_attach=False,
|
||||
|
@ -560,6 +592,43 @@ class TestDriverBlockDevice(test.NoDBTestCase):
|
|||
self.virt_driver, wait_func)
|
||||
self.assertEqual(test_bdm.volume_id, 'fake-volume-id-2')
|
||||
|
||||
def test_snapshot_attach_fail_volume(self):
|
||||
fail_volume_snapshot = self.snapshot_bdm.copy()
|
||||
fail_volume_snapshot['volume_id'] = None
|
||||
test_bdm = self.driver_classes['snapshot'](fail_volume_snapshot)
|
||||
|
||||
snapshot = {'id': 'fake-volume-id-1',
|
||||
'attach_status': 'detached'}
|
||||
volume = {'id': 'fake-volume-id-2',
|
||||
'attach_status': 'detached'}
|
||||
|
||||
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx,
|
||||
**{'uuid': 'fake-uuid'})
|
||||
with contextlib.nested(
|
||||
mock.patch.object(self.volume_api, 'get_snapshot',
|
||||
return_value=snapshot),
|
||||
mock.patch.object(self.volume_api, 'create', return_value=volume),
|
||||
mock.patch.object(self.volume_api, 'delete'),
|
||||
) as (vol_get_snap, vol_create, vol_delete):
|
||||
wait_func = mock.MagicMock()
|
||||
mock_exception = exception.VolumeNotCreated(volume_id=volume['id'],
|
||||
seconds=1,
|
||||
attempts=1,
|
||||
volume_status='error')
|
||||
wait_func.side_effect = mock_exception
|
||||
self.assertRaises(exception.VolumeNotCreated,
|
||||
test_bdm.attach, context=self.context,
|
||||
instance=instance,
|
||||
volume_api=self.volume_api,
|
||||
virt_driver=self.virt_driver,
|
||||
wait_func=wait_func)
|
||||
|
||||
vol_get_snap.assert_called_once_with(
|
||||
self.context, 'fake-snapshot-id-1')
|
||||
vol_create.assert_called_once_with(
|
||||
self.context, 3, '', '', snapshot, availability_zone=None)
|
||||
vol_delete.assert_called_once_with(self.context, volume['id'])
|
||||
|
||||
def test_snapshot_attach_volume(self):
|
||||
test_bdm = self.driver_classes['snapshot'](
|
||||
self.snapshot_bdm)
|
||||
|
@ -604,6 +673,39 @@ class TestDriverBlockDevice(test.NoDBTestCase):
|
|||
self.virt_driver, wait_func)
|
||||
self.assertEqual(test_bdm.volume_id, 'fake-volume-id-2')
|
||||
|
||||
def test_image_attach_fail_volume(self):
|
||||
fail_volume_image = self.image_bdm.copy()
|
||||
fail_volume_image['volume_id'] = None
|
||||
test_bdm = self.driver_classes['image'](fail_volume_image)
|
||||
|
||||
image = {'id': 'fake-image-id-1'}
|
||||
volume = {'id': 'fake-volume-id-2',
|
||||
'attach_status': 'detached'}
|
||||
|
||||
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx,
|
||||
**{'uuid': 'fake-uuid'})
|
||||
with contextlib.nested(
|
||||
mock.patch.object(self.volume_api, 'create', return_value=volume),
|
||||
mock.patch.object(self.volume_api, 'delete'),
|
||||
) as (vol_create, vol_delete):
|
||||
wait_func = mock.MagicMock()
|
||||
mock_exception = exception.VolumeNotCreated(volume_id=volume['id'],
|
||||
seconds=1,
|
||||
attempts=1,
|
||||
volume_status='error')
|
||||
wait_func.side_effect = mock_exception
|
||||
self.assertRaises(exception.VolumeNotCreated,
|
||||
test_bdm.attach, context=self.context,
|
||||
instance=instance,
|
||||
volume_api=self.volume_api,
|
||||
virt_driver=self.virt_driver,
|
||||
wait_func=wait_func)
|
||||
|
||||
vol_create.assert_called_once_with(
|
||||
self.context, 1, '', '', image_id=image['id'],
|
||||
availability_zone=None)
|
||||
vol_delete.assert_called_once_with(self.context, volume['id'])
|
||||
|
||||
def test_image_attach_volume(self):
|
||||
test_bdm = self.driver_classes['image'](
|
||||
self.image_bdm)
|
||||
|
@ -626,6 +728,38 @@ class TestDriverBlockDevice(test.NoDBTestCase):
|
|||
self.virt_driver)
|
||||
self.assertEqual(test_bdm.volume_id, 'fake-volume-id-2')
|
||||
|
||||
def test_blank_attach_fail_volume(self):
|
||||
no_blank_volume = self.blank_bdm.copy()
|
||||
no_blank_volume['volume_id'] = None
|
||||
test_bdm = self.driver_classes['blank'](no_blank_volume)
|
||||
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx,
|
||||
**{'uuid': 'fake-uuid'})
|
||||
volume = {'id': 'fake-volume-id-2',
|
||||
'display_name': 'fake-uuid-blank-vol'}
|
||||
|
||||
with contextlib.nested(
|
||||
mock.patch.object(self.volume_api, 'create', return_value=volume),
|
||||
mock.patch.object(self.volume_api, 'delete'),
|
||||
) as (vol_create, vol_delete):
|
||||
wait_func = mock.MagicMock()
|
||||
mock_exception = exception.VolumeNotCreated(volume_id=volume['id'],
|
||||
seconds=1,
|
||||
attempts=1,
|
||||
volume_status='error')
|
||||
wait_func.side_effect = mock_exception
|
||||
self.assertRaises(exception.VolumeNotCreated,
|
||||
test_bdm.attach, context=self.context,
|
||||
instance=instance,
|
||||
volume_api=self.volume_api,
|
||||
virt_driver=self.virt_driver,
|
||||
wait_func=wait_func)
|
||||
|
||||
vol_create.assert_called_once_with(
|
||||
self.context, test_bdm.volume_size, 'fake-uuid-blank-vol',
|
||||
'', availability_zone=instance.availability_zone)
|
||||
vol_delete.assert_called_once_with(
|
||||
self.context, volume['id'])
|
||||
|
||||
def test_blank_attach_volume(self):
|
||||
no_blank_volume = self.blank_bdm.copy()
|
||||
no_blank_volume['volume_id'] = None
|
||||
|
|
|
@ -22,8 +22,10 @@ from oslo_utils import excutils
|
|||
import six
|
||||
|
||||
from nova import block_device
|
||||
from nova import exception
|
||||
from nova.i18n import _LE
|
||||
from nova.i18n import _LI
|
||||
from nova.i18n import _LW
|
||||
from nova import objects
|
||||
from nova.objects import base as obj_base
|
||||
from nova.volume import encryptors
|
||||
|
@ -303,6 +305,19 @@ class DriverVolumeBlockDevice(DriverBlockDevice):
|
|||
pass
|
||||
super(DriverVolumeBlockDevice, self).save()
|
||||
|
||||
def _call_wait_func(self, context, wait_func, volume_api, volume_id):
|
||||
try:
|
||||
wait_func(context, volume_id)
|
||||
except exception.VolumeNotCreated:
|
||||
with excutils.save_and_reraise_exception():
|
||||
if self['delete_on_termination']:
|
||||
try:
|
||||
volume_api.delete(context, volume_id)
|
||||
except Exception as exc:
|
||||
LOG.warn(_LW('Failed to delete volume: %(volume_id)s '
|
||||
'due to %(exc)s'),
|
||||
{'volume_id': volume_id, 'exc': exc})
|
||||
|
||||
|
||||
class DriverSnapshotBlockDevice(DriverVolumeBlockDevice):
|
||||
|
||||
|
@ -319,7 +334,7 @@ class DriverSnapshotBlockDevice(DriverVolumeBlockDevice):
|
|||
vol = volume_api.create(context, self.volume_size, '', '',
|
||||
snapshot, availability_zone=av_zone)
|
||||
if wait_func:
|
||||
wait_func(context, vol['id'])
|
||||
self._call_wait_func(context, wait_func, volume_api, vol['id'])
|
||||
|
||||
self.volume_id = vol['id']
|
||||
|
||||
|
@ -342,7 +357,7 @@ class DriverImageBlockDevice(DriverVolumeBlockDevice):
|
|||
'', '', image_id=self.image_id,
|
||||
availability_zone=av_zone)
|
||||
if wait_func:
|
||||
wait_func(context, vol['id'])
|
||||
self._call_wait_func(context, wait_func, volume_api, vol['id'])
|
||||
|
||||
self.volume_id = vol['id']
|
||||
|
||||
|
@ -364,7 +379,7 @@ class DriverBlankBlockDevice(DriverVolumeBlockDevice):
|
|||
vol = volume_api.create(context, self.volume_size, vol_name, '',
|
||||
availability_zone=av_zone)
|
||||
if wait_func:
|
||||
wait_func(context, vol['id'])
|
||||
self._call_wait_func(context, wait_func, volume_api, vol['id'])
|
||||
|
||||
self.volume_id = vol['id']
|
||||
|
||||
|
|
Loading…
Reference in New Issue