Merge "Add extend volume support for fileio"

This commit is contained in:
Zuul 2017-11-15 17:27:23 +00:00 committed by Gerrit Code Review
commit 090e4068c0
6 changed files with 85 additions and 1 deletions

View File

@ -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

View File

@ -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')

View File

@ -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."""

View File

@ -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")

View File

@ -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.

View File

@ -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,