Merge "Add extend volume support for fileio"
This commit is contained in:
commit
090e4068c0
|
@ -92,6 +92,21 @@ notes=See notes for attach volume operation.
|
|||
cli=
|
||||
driver-impl-powervm=complete
|
||||
|
||||
[operation.extend-volume]
|
||||
title=Extend block volume attached to instance
|
||||
status=optional
|
||||
notes=The extend volume operation provides a means to extend
|
||||
the size of an attached volume. This allows volume size
|
||||
to be expanded without interruption of service.
|
||||
In a cloud model it would be more typical to just
|
||||
spin up a new instance with large storage, so the ability to
|
||||
extend the size of an attached volume is for those cases
|
||||
where the instance is considered to be more of a pet than cattle.
|
||||
Therefore this operation is not considered to be mandatory to support.
|
||||
cli=cinder extend <volume> <new_size>
|
||||
driver-impl-powervm=partial
|
||||
driver-notes-powervm=Extend volume only supported for fileio volumes.
|
||||
|
||||
[operation.maintenance-mode]
|
||||
title=Set the host in a maintenance mode
|
||||
status=optional
|
||||
|
|
|
@ -20,6 +20,7 @@ from nova_powervm.tests.virt.powervm.volume import test_driver as test_vol
|
|||
from nova_powervm.virt.powervm import exception as p_exc
|
||||
from nova_powervm.virt.powervm.volume import fileio as v_drv
|
||||
from pypowervm import const as pvm_const
|
||||
from pypowervm import exceptions as pvm_exc
|
||||
from pypowervm.tests import test_fixtures as pvm_fx
|
||||
from pypowervm.wrappers import base_partition as pvm_bp
|
||||
from pypowervm.wrappers import storage as pvm_stg
|
||||
|
@ -130,6 +131,22 @@ class TestFileIOVolumeAdapter(test_vol.TestVolumeAdapter):
|
|||
backstore_type=pvm_stg.BackStoreType.FILE_IO)
|
||||
self.assertEqual(0, mock_build_map.call_count)
|
||||
|
||||
@mock.patch('pypowervm.tasks.partition.get_mgmt_partition', autospec=True)
|
||||
@mock.patch('pypowervm.tasks.storage.rescan_vstor', autospec=True)
|
||||
def test_extend_volume(self, mock_rescan, mock_get_mgmt_partition):
|
||||
# FileIO driver can only have 1 uuid in vol_drv.vios_uuids
|
||||
mock_vios = mock.Mock(uuid='uuid1')
|
||||
mock_get_mgmt_partition.return_value = mock_vios
|
||||
self.vol_drv.extend_volume()
|
||||
mock_rescan.assert_called_once_with(self.vol_drv.vios_uuids[0],
|
||||
"fake_path", adapter=self.adpt)
|
||||
mock_rescan.side_effect = pvm_exc.JobRequestFailed(
|
||||
operation_name='RescanVirtualDisk', error='fake_err')
|
||||
self.assertRaises(p_exc.VolumeExtendFailed, self.vol_drv.extend_volume)
|
||||
mock_rescan.side_effect = pvm_exc.VstorNotFound(
|
||||
stor_udid='stor_udid', vios_uuid='uuid')
|
||||
self.assertRaises(p_exc.VolumeExtendFailed, self.vol_drv.extend_volume)
|
||||
|
||||
@mock.patch('pypowervm.entities.Entry.uuid',
|
||||
new_callable=mock.PropertyMock)
|
||||
@mock.patch('pypowervm.tasks.partition.get_mgmt_partition')
|
||||
|
|
|
@ -95,7 +95,8 @@ class PowerVMDriver(driver.ComputeDriver):
|
|||
"supports_recreate": True,
|
||||
"supports_migrate_to_same_host": False,
|
||||
"supports_attach_interface": True,
|
||||
"supports_device_tagging": False
|
||||
"supports_device_tagging": False,
|
||||
"supports_extend_volume": True
|
||||
}
|
||||
|
||||
def __init__(self, virtapi):
|
||||
|
@ -757,6 +758,12 @@ class PowerVMDriver(driver.ComputeDriver):
|
|||
# to revise in the future as volume connectors evolve.
|
||||
instance.save()
|
||||
|
||||
def extend_volume(self, connection_info, instance):
|
||||
"""Resize an attached volume"""
|
||||
vol_drv = vol_attach.build_volume_driver(
|
||||
self.adapter, self.host_uuid, instance, connection_info)
|
||||
vol_drv.extend_volume()
|
||||
|
||||
def detach_volume(self, connection_info, instance, mountpoint,
|
||||
encryption=None):
|
||||
"""Detach the volume attached to the instance."""
|
||||
|
|
|
@ -101,6 +101,11 @@ class VolumeAttachFailed(nex.NovaException):
|
|||
"machine %(instance_name)s. %(reason)s")
|
||||
|
||||
|
||||
class VolumeExtendFailed(nex.NovaException):
|
||||
msg_fmt = _("Unable to extend volume (id: %(volume_id)s) on virtual "
|
||||
"machine %(instance_name)s.")
|
||||
|
||||
|
||||
class VolumeDetachFailed(nex.NovaException):
|
||||
msg_fmt = _("Unable to detach volume (id: %(volume_id)s) from virtual "
|
||||
"machine %(instance_name)s. %(reason)s")
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
import abc
|
||||
import six
|
||||
|
||||
from oslo_log import log as logging
|
||||
from pypowervm import exceptions as pvm_exc
|
||||
from pypowervm.tasks import partition as pvm_partition
|
||||
from pypowervm.tasks import storage as tsk_stg
|
||||
from pypowervm.utils import transaction as pvm_tx
|
||||
from pypowervm.wrappers import virtual_io_server as pvm_vios
|
||||
|
||||
|
@ -25,6 +28,7 @@ from nova_powervm.virt.powervm import exception as exc
|
|||
from nova_powervm.virt.powervm import vm
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
LOCAL_FEED_TASK = 'local_feed_task'
|
||||
|
||||
|
||||
|
@ -228,6 +232,35 @@ class PowerVMVolumeAdapter(object):
|
|||
if self.stg_ftsk.name == LOCAL_FEED_TASK:
|
||||
self.stg_ftsk.execute()
|
||||
|
||||
def extend_volume(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _extend_volume(self, udid):
|
||||
"""Rescan virtual disk so client VM can see extended size"""
|
||||
resized = False
|
||||
error = False
|
||||
for vios_uuid in self.vios_uuids:
|
||||
try:
|
||||
LOG.debug("Rescanning volume %(vol)s for vios uuid %(uuid)s",
|
||||
dict(vol=self.volume_id, uuid=vios_uuid),
|
||||
instance=self.instance)
|
||||
tsk_stg.rescan_vstor(vios_uuid, udid, adapter=self.adapter)
|
||||
resized = True
|
||||
except pvm_exc.VstorNotFound:
|
||||
LOG.info("Failed to find volume %(vol)s for VIOS "
|
||||
"UUID %(uuid)s during extend operation.",
|
||||
{'vol': self.volume_id, 'uuid': vios_uuid},
|
||||
instance=self.instance)
|
||||
except pvm_exc.JobRequestFailed as e:
|
||||
error = True
|
||||
LOG.error("Failed to rescan volume %(vol)s for VIOS "
|
||||
"UUID %(uuid)s. %(reason)s",
|
||||
{'vol': self.volume_id, 'uuid': vios_uuid,
|
||||
'reason': six.text_type(e)}, instance=self.instance)
|
||||
if not resized or error:
|
||||
raise exc.VolumeExtendFailed(volume_id=self.volume_id,
|
||||
instance_name=self.instance.name)
|
||||
|
||||
def disconnect_volume(self, slot_mgr):
|
||||
"""Disconnect the volume.
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import os
|
|||
import six
|
||||
from taskflow import task
|
||||
|
||||
from nova import exception as nova_exc
|
||||
from nova_powervm import conf as cfg
|
||||
from nova_powervm.virt.powervm import exception as p_exc
|
||||
from nova_powervm.virt.powervm import vm
|
||||
|
@ -136,6 +137,12 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
|
|||
self.stg_ftsk.add_post_execute(task.FunctorTask(
|
||||
set_slot_info, name='file_io_slot_%s' % path))
|
||||
|
||||
def extend_volume(self):
|
||||
path = self._get_path()
|
||||
if path is None:
|
||||
raise nova_exc.InvalidBDM()
|
||||
self._extend_volume(path)
|
||||
|
||||
def _disconnect_volume(self, slot_mgr):
|
||||
# Build the match function
|
||||
match_func = tsk_map.gen_match_func(pvm_stg.VDisk,
|
||||
|
|
Loading…
Reference in New Issue