Support online volume extension
Cinder supports extending volumes in use since API microversion 3.42. Check the supported microversion and use this feature if supported, instead of detaching the volume. Story: 2011229 Task: 51086 Change-Id: If67bdd2bc7a055d9b0c22772528f6ab08697f486
This commit is contained in:
parent
0b84e5be0d
commit
e26f779d92
@ -27,6 +27,8 @@ from heat.engine import translation
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
CINDER_MICROVERSIONS = (MICROVERSION_EXTEND_INUSE,) = ('3.42',)
|
||||
|
||||
|
||||
class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
||||
"""A resource that implements Cinder volumes.
|
||||
@ -369,6 +371,9 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
||||
def _ready_to_extend_volume(self):
|
||||
vol = self.client().volumes.get(self.resource_id)
|
||||
expected_status = ('available',)
|
||||
if self.client_plugin().is_version_supported(
|
||||
MICROVERSION_EXTEND_INUSE):
|
||||
expected_status = ('available', 'in-use')
|
||||
if vol.status in expected_status:
|
||||
LOG.debug("Volume %s is ready to extend.", vol.id)
|
||||
return True
|
||||
@ -381,6 +386,9 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
||||
return False
|
||||
|
||||
expected_status = ('available',)
|
||||
if self.client_plugin().is_version_supported(
|
||||
MICROVERSION_EXTEND_INUSE):
|
||||
expected_status = ('available', 'in-use')
|
||||
if vol.status not in expected_status:
|
||||
LOG.info("Resize failed: Volume %(vol)s "
|
||||
"is in %(status)s state.",
|
||||
@ -490,7 +498,9 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
||||
|
||||
elif new_size > vol.size:
|
||||
prg_resize = progress.VolumeResizeProgress(size=new_size)
|
||||
prg_detach, prg_attach = self._detach_attach_progress(vol)
|
||||
if not self.client_plugin().is_version_supported(
|
||||
MICROVERSION_EXTEND_INUSE):
|
||||
prg_detach, prg_attach = self._detach_attach_progress(vol)
|
||||
|
||||
return prg_restore, prg_detach, prg_resize, prg_access, prg_attach
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
import copy
|
||||
from unittest import mock
|
||||
|
||||
from cinderclient import api_versions
|
||||
from cinderclient import exceptions as cinder_exp
|
||||
from oslo_config import cfg
|
||||
|
||||
@ -625,7 +624,7 @@ class VolumeTest(vt_base.VolumeTestCase):
|
||||
self.create_volume(self.t, stack, 'DataVolume', no_create=True)
|
||||
|
||||
cinder.CinderClientPlugin._create.assert_called_once_with(
|
||||
version=api_versions.MAX_VERSION)
|
||||
version='3.0')
|
||||
self.m_restore.assert_called_once_with('backup-123')
|
||||
self.cinder_fc.volumes.get.assert_called_with('vol-123')
|
||||
self.cinder_fc.volumes.update.assert_called_once_with(
|
||||
@ -654,7 +653,7 @@ class VolumeTest(vt_base.VolumeTestCase):
|
||||
str(ex))
|
||||
|
||||
cinder.CinderClientPlugin._create.assert_called_once_with(
|
||||
version=api_versions.MAX_VERSION)
|
||||
version='3.0')
|
||||
self.m_restore.assert_called_once_with('backup-123')
|
||||
self.cinder_fc.volumes.update.assert_called_once_with(
|
||||
fv.id, description=vol_name, name=vol_name)
|
||||
|
@ -449,6 +449,36 @@ class CinderVolumeTest(vt_base.VolumeTestCase):
|
||||
self.stack_name = 'test_cvolume_extend_att_stack'
|
||||
self._update_if_attached(self.stack_name)
|
||||
|
||||
def test_cinder_volume_extend_attached_live(self):
|
||||
self.patchobject(cinder.CinderClientPlugin, 'get_max_microversion',
|
||||
return_value='3.42')
|
||||
self.stack_name = 'test_cvolume_extend_live_att_stack'
|
||||
|
||||
fv = vt_base.FakeVolume('available',
|
||||
size=1, attachments=[])
|
||||
self._mock_create_volume(vt_base.FakeVolume('creating'),
|
||||
self.stack_name,
|
||||
extra_get_mocks=[
|
||||
fv, vt_base.FakeVolume('extending'),
|
||||
vt_base.FakeVolume('extending'),
|
||||
vt_base.FakeVolume('in-use')])
|
||||
|
||||
stack = utils.parse_stack(self.t, stack_name=self.stack_name)
|
||||
|
||||
rsrc = self.create_volume(self.t, stack, 'volume')
|
||||
|
||||
props = copy.deepcopy(rsrc.properties.data)
|
||||
props['size'] = 2
|
||||
after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
|
||||
|
||||
update_task = scheduler.TaskRunner(rsrc.update, after)
|
||||
self.assertIsNone(update_task())
|
||||
|
||||
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
||||
self.cinder_fc.volumes.extend.assert_called_once_with(fv.id, 2)
|
||||
self.fc.volumes.get_server_volume.assert_not_called()
|
||||
self.fc.volumes.delete_server_volume.assert_not_called()
|
||||
|
||||
def test_cinder_volume_extend_created_from_backup_with_same_size(self):
|
||||
self.stack_name = 'test_cvolume_extend_snapsht_stack'
|
||||
|
||||
@ -1386,6 +1416,11 @@ class CinderVolumeTest(vt_base.VolumeTestCase):
|
||||
self._mock_create_volume(vt_base.FakeVolume('creating'),
|
||||
self.stack_name,
|
||||
extra_get_mocks=[
|
||||
vt_base.FakeVolume('extending'),
|
||||
vt_base.FakeVolume('reserved'),
|
||||
vt_base.FakeVolume('in-use'),
|
||||
vt_base.FakeVolume('available'),
|
||||
vt_base.FakeVolume('creating'),
|
||||
vt_base.FakeVolume('extending'),
|
||||
vt_base.FakeVolume('reserved'),
|
||||
vt_base.FakeVolume('in-use'),
|
||||
@ -1401,6 +1436,14 @@ class CinderVolumeTest(vt_base.VolumeTestCase):
|
||||
self.assertEqual(False, rsrc._ready_to_extend_volume())
|
||||
self.assertEqual(True, rsrc._ready_to_extend_volume())
|
||||
|
||||
self.patchobject(cinder.CinderClientPlugin, 'get_max_microversion',
|
||||
return_value='3.42')
|
||||
self.assertEqual(False, rsrc._ready_to_extend_volume())
|
||||
self.assertEqual(False, rsrc._ready_to_extend_volume())
|
||||
self.assertEqual(False, rsrc._ready_to_extend_volume())
|
||||
self.assertEqual(True, rsrc._ready_to_extend_volume())
|
||||
self.assertEqual(True, rsrc._ready_to_extend_volume())
|
||||
|
||||
def test_try_detach_volume_if_server_was_temporarily_in_error(self):
|
||||
self.stack_name = 'test_cvolume_detach_server_in_error_stack'
|
||||
fva = vt_base.FakeVolume('in-use')
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from cinderclient import api_versions
|
||||
from cinderclient.v3 import client as cinderclient
|
||||
|
||||
from heat.engine.clients.os import cinder
|
||||
@ -34,7 +33,7 @@ class VolumeTestCase(common.HeatTestCase):
|
||||
self.cinder_fc = cinderclient.Client('username', 'password')
|
||||
self.cinder_fc.volume_api_version = 3
|
||||
self.patchobject(cinder.CinderClientPlugin, 'get_max_microversion',
|
||||
return_value=api_versions.MAX_VERSION)
|
||||
return_value='3.0')
|
||||
self.patchobject(cinder.CinderClientPlugin, '_create',
|
||||
return_value=self.cinder_fc)
|
||||
self.patchobject(nova.NovaClientPlugin, 'client',
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The ``OS::Cinder::Volume`` resource type now supports extending volumes
|
||||
in use. Note that this requires that Cinder supports API microversion
|
||||
3.42 or later.
|
Loading…
Reference in New Issue
Block a user