Allow vios to be filtered for rebuild

During rebuild process all the active VIOS are considered as valid.
In case of some powervm env a VIOS might not own any IO and is not
a valid candiate for rebuild.

Adding a vios_uuids method to define the valid vios for a given
volume driver. This property can be used further in all the
connect and disconnect operations as well. That will be done as
part of a future changeset.

Change-Id: I936c12a8b1fff431fcf3098aca57cedcdbf32b0b
This commit is contained in:
Shyama Venugopal 2017-04-27 15:31:23 -04:00
parent fecc5ec0db
commit c614c3a9a7
4 changed files with 63 additions and 9 deletions

View File

@ -121,6 +121,32 @@ class TestSwiftSlotManager(test.TestCase):
p_exc.InvalidRebuild, self.slot_mgr.init_recreate_map, mock.Mock(),
self._vol_drv_iter())
@mock.patch('pypowervm.tasks.slot_map.RebuildSlotMap')
@mock.patch('pypowervm.tasks.storage.ComprehensiveScrub')
def test_init_recreate_map_fileio(self, mock_ftsk, mock_rebuild_slot):
vios1, vios2 = mock.Mock(uuid='uuid1'), mock.Mock(uuid='uuid2')
mock_ftsk.return_value.feed = [vios1, vios2]
expected_vio_wrap = [vios1, vios2]
self.slot_mgr.init_recreate_map(mock.Mock(), self._vol_drv_iter_2())
self.assertEqual(1, mock_ftsk.call_count)
mock_rebuild_slot.assert_called_once_with(
self.slot_mgr, expected_vio_wrap,
{'udidvscsi': ['uuid1'], 'udid': ['uuid1']}, [])
def _vol_drv_iter_2(self):
mock_fileio = mock.Mock()
mock_fileio.vol_type.return_value = 'fileio'
mock_fileio.is_volume_on_vios.side_effect = ((True, 'udid'),
(False, None))
mock_scsi = mock.Mock()
mock_scsi.vol_type.return_value = 'vscsi'
mock_scsi.is_volume_on_vios.side_effect = ((True, 'udidvscsi'),
(False, None))
vol_drv = [mock_fileio, mock_scsi]
for type in vol_drv:
yield mock.Mock(), type
def _vol_drv_iter(self):
mock_scsi = mock.Mock()
mock_scsi.vol_type.return_value = 'vscsi'

View File

@ -162,3 +162,12 @@ class TestFileIOVolumeAdapter(test_vol.TestVolumeAdapter):
self.assertRaises(
p_exc.VolumePreMigrationFailed,
self.vol_drv.pre_live_migration_on_destination, mock.ANY)
@mock.patch('nova_powervm.virt.powervm.volume.fileio.FileIOVolumeAdapter.'
'vios_uuids', new_callable=mock.PropertyMock)
def test_is_volume_on_vios(self, mock_vios_uuids):
mock_vios_uuids.return_value = ['uuid1']
vol_found, vol_path = self.vol_drv.is_volume_on_vios(
mock.Mock(uuid='uuid2'))
self.assertFalse(vol_found)
self.assertIsNone(vol_path)

View File

@ -17,6 +17,7 @@
import abc
import six
from pypowervm.tasks import partition as pvm_partition
from pypowervm.utils import transaction as pvm_tx
from pypowervm.wrappers import virtual_io_server as pvm_vios
@ -108,6 +109,12 @@ class PowerVMVolumeAdapter(object):
"""List of pypowervm XAGs needed to support this adapter."""
raise NotImplementedError()
@property
def vios_uuids(self):
"""List the UUIDs of the Virtual I/O Servers hosting the storage."""
vios_wraps = pvm_partition.get_active_vioses(self.adapter)
return [wrap.uuid for wrap in vios_wraps]
@classmethod
def vol_type(cls):
"""The type of volume supported by this driver."""

View File

@ -40,6 +40,12 @@ LOG = logging.getLogger(__name__)
class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
"""Base class for connecting file based Cinder Volumes to PowerVM VMs."""
def __init__(self, adapter, host_uuid, instance, connection_info,
stg_ftsk=None):
super(FileIOVolumeAdapter, self).__init__(
adapter, host_uuid, instance, connection_info, stg_ftsk=stg_ftsk)
self._nl_vios_ids = None
@classmethod
def min_xags(cls):
return [pvm_const.XAG.VIO_SMAP]
@ -54,6 +60,15 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
"""Return the path to the file to connect."""
pass
@property
def vios_uuids(self):
"""List the UUIDs of the Virtual I/O Servers hosting the storage."""
# Get the hosting UUID
if self._nl_vios_ids is None:
nl_vios_wrap = partition.get_mgmt_partition(self.adapter)
self._nl_vios_ids = [nl_vios_wrap.uuid]
return self._nl_vios_ids
def pre_live_migration_on_destination(self, mig_data):
"""Perform pre live migration steps for the volume on the target host.
@ -78,9 +93,6 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
volume_id=self.volume_id, instance_name=self.instance.name)
def _connect_volume(self, slot_mgr):
# Get the hosting UUID
nl_vios_wrap = partition.get_mgmt_partition(self.adapter)
vios_uuid = nl_vios_wrap.uuid
path = self._get_path()
# Get the File Path
fio = pvm_stg.FileIO.bld(
@ -89,7 +101,7 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
def add_func(vios_w):
# If the vios doesn't match, just return
if vios_w.uuid != vios_uuid:
if vios_w.uuid not in self.vios_uuids:
return None
LOG.info(_LI("Adding logical volume disk connection between VM "
@ -126,9 +138,6 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
set_slot_info, name='file_io_slot_%s' % path))
def _disconnect_volume(self, slot_mgr):
# Get the hosting UUID
nl_vios_wrap = partition.get_mgmt_partition(self.adapter)
vios_uuid = nl_vios_wrap.uuid
# Build the match function
match_func = tsk_map.gen_match_func(pvm_stg.VDisk,
names=[self._get_path()])
@ -136,7 +145,7 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
# Make sure the remove function will run within the transaction manager
def rm_func(vios_w):
# If the vios doesn't match, just return
if vios_w.uuid != vios_uuid:
if vios_w.uuid not in self.vios_uuids:
return None
LOG.info(_LI("Disconnecting instance %(inst)s from storage "
@ -150,7 +159,7 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
self.stg_ftsk.add_functor_subtask(rm_func)
# Find the disk directly.
vios_w = self.stg_ftsk.wrapper_tasks[vios_uuid].wrapper
vios_w = self.stg_ftsk.wrapper_tasks[self.vios_uuids[0]].wrapper
mappings = tsk_map.find_maps(vios_w.scsi_mappings,
client_lpar_id=self.vm_uuid,
match_func=match_func)
@ -168,6 +177,9 @@ class FileIOVolumeAdapter(v_driver.PowerVMVolumeAdapter):
otherwise.
:return: The file path.
"""
if vios_w.uuid not in self.vios_uuids:
return False, None
vol_path = self._get_path()
vol_found = os.path.exists(vol_path)
return vol_found, vol_path