vSCSI In-tree Backports
This contains backports for minor code changes made during in-tree driver vSCSI development [1]. [1] https://review.openstack.org/#/c/526094/ Change-Id: I60788e8756df2dfec5f0a407ca149a8ea3cedd53
This commit is contained in:
parent
edae7d1168
commit
066369594e
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2014, 2018 IBM Corp.
|
# Copyright IBM Corp. and contributors
|
||||||
#
|
#
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
|
@ -23,6 +23,7 @@ from oslo_serialization import jsonutils
|
||||||
|
|
||||||
from nova import block_device as nova_block_device
|
from nova import block_device as nova_block_device
|
||||||
from nova.compute import task_states
|
from nova.compute import task_states
|
||||||
|
from nova import conf as cfg
|
||||||
from nova import exception as exc
|
from nova import exception as exc
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.objects import base as obj_base
|
from nova.objects import base as obj_base
|
||||||
|
@ -49,6 +50,7 @@ from nova_powervm.virt.powervm import exception as p_exc
|
||||||
from nova_powervm.virt.powervm import live_migration as lpm
|
from nova_powervm.virt.powervm import live_migration as lpm
|
||||||
from nova_powervm.virt.powervm import vm
|
from nova_powervm.virt.powervm import vm
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
logging.basicConfig()
|
logging.basicConfig()
|
||||||
|
|
||||||
|
@ -218,7 +220,7 @@ class TestPowerVMDriver(test.NoDBTestCase):
|
||||||
|
|
||||||
vol_connector = self.drv.get_volume_connector(mock.Mock())
|
vol_connector = self.drv.get_volume_connector(mock.Mock())
|
||||||
self.assertIsNotNone(vol_connector['wwpns'])
|
self.assertIsNotNone(vol_connector['wwpns'])
|
||||||
self.assertIsNotNone(vol_connector['host'])
|
self.assertEqual(vol_connector['host'], CONF.host)
|
||||||
self.assertEqual('fake_iqn1', vol_connector['initiator'])
|
self.assertEqual('fake_iqn1', vol_connector['initiator'])
|
||||||
|
|
||||||
def test_setup_disk_adapter(self):
|
def test_setup_disk_adapter(self):
|
||||||
|
@ -1269,7 +1271,7 @@ class TestPowerVMDriver(test.NoDBTestCase):
|
||||||
with mock.patch.object(self.inst, 'save') as mock_save:
|
with mock.patch.object(self.inst, 'save') as mock_save:
|
||||||
# Invoke the method.
|
# Invoke the method.
|
||||||
self.drv.attach_volume('context', mock_bdm.get('connection_info'),
|
self.drv.attach_volume('context', mock_bdm.get('connection_info'),
|
||||||
self.inst, mock.Mock())
|
self.inst, mock.sentinel.stg_ftsk)
|
||||||
|
|
||||||
mock_bld_slot_mgr.assert_called_once_with(self.inst,
|
mock_bld_slot_mgr.assert_called_once_with(self.inst,
|
||||||
self.drv.store_api)
|
self.drv.store_api)
|
||||||
|
@ -1277,7 +1279,7 @@ class TestPowerVMDriver(test.NoDBTestCase):
|
||||||
self.vol_drv.connect_volume.assert_called_once_with(
|
self.vol_drv.connect_volume.assert_called_once_with(
|
||||||
mock_bld_slot_mgr.return_value)
|
mock_bld_slot_mgr.return_value)
|
||||||
mock_bld_slot_mgr.return_value.save.assert_called_once_with()
|
mock_bld_slot_mgr.return_value.save.assert_called_once_with()
|
||||||
self.assertTrue(mock_save.called)
|
mock_save.assert_called_once_with()
|
||||||
|
|
||||||
@mock.patch('nova_powervm.virt.powervm.vm.instance_exists', autospec=True)
|
@mock.patch('nova_powervm.virt.powervm.vm.instance_exists', autospec=True)
|
||||||
@mock.patch('nova_powervm.virt.powervm.slot.build_slot_mgr', autospec=True)
|
@mock.patch('nova_powervm.virt.powervm.slot.build_slot_mgr', autospec=True)
|
||||||
|
@ -1290,7 +1292,7 @@ class TestPowerVMDriver(test.NoDBTestCase):
|
||||||
mock_bdm = self._fake_bdms()['block_device_mapping'][0]
|
mock_bdm = self._fake_bdms()['block_device_mapping'][0]
|
||||||
# Invoke the method, good path test.
|
# Invoke the method, good path test.
|
||||||
self.drv.detach_volume('context', mock_bdm.get('connection_info'),
|
self.drv.detach_volume('context', mock_bdm.get('connection_info'),
|
||||||
self.inst, mock.Mock())
|
self.inst, mock.sentinel.stg_ftsk)
|
||||||
|
|
||||||
mock_bld_slot_mgr.assert_called_once_with(self.inst,
|
mock_bld_slot_mgr.assert_called_once_with(self.inst,
|
||||||
self.drv.store_api)
|
self.drv.store_api)
|
||||||
|
@ -1302,7 +1304,7 @@ class TestPowerVMDriver(test.NoDBTestCase):
|
||||||
# Invoke the method, instance doesn't exist, no migration
|
# Invoke the method, instance doesn't exist, no migration
|
||||||
self.vol_drv.disconnect_volume.reset_mock()
|
self.vol_drv.disconnect_volume.reset_mock()
|
||||||
self.drv.detach_volume('context', mock_bdm.get('connection_info'),
|
self.drv.detach_volume('context', mock_bdm.get('connection_info'),
|
||||||
self.inst, mock.Mock())
|
self.inst, mock.sentinel.stg_ftsk)
|
||||||
# Verify the disconnect volume was not invoked
|
# Verify the disconnect volume was not invoked
|
||||||
self.assertEqual(0, self.vol_drv.disconnect_volume.call_count)
|
self.assertEqual(0, self.vol_drv.disconnect_volume.call_count)
|
||||||
|
|
||||||
|
@ -1312,7 +1314,7 @@ class TestPowerVMDriver(test.NoDBTestCase):
|
||||||
self.drv.live_migrations[self.inst.uuid] = mig
|
self.drv.live_migrations[self.inst.uuid] = mig
|
||||||
with mock.patch.object(mig, 'cleanup_volume') as mock_clnup:
|
with mock.patch.object(mig, 'cleanup_volume') as mock_clnup:
|
||||||
self.drv.detach_volume('context', mock_bdm.get('connection_info'),
|
self.drv.detach_volume('context', mock_bdm.get('connection_info'),
|
||||||
self.inst, mock.Mock())
|
self.inst, mock.sentinel.stg_ftsk)
|
||||||
# The cleanup should have been called since there was a migration
|
# The cleanup should have been called since there was a migration
|
||||||
self.assertEqual(1, mock_clnup.call_count)
|
self.assertEqual(1, mock_clnup.call_count)
|
||||||
# Verify the disconnect volume was not invoked
|
# Verify the disconnect volume was not invoked
|
||||||
|
|
|
@ -754,7 +754,13 @@ class PowerVMDriver(driver.ComputeDriver):
|
||||||
instance.save()
|
instance.save()
|
||||||
|
|
||||||
def extend_volume(self, connection_info, instance):
|
def extend_volume(self, connection_info, instance):
|
||||||
"""Resize an attached volume"""
|
"""Extend the disk attached to the instance.
|
||||||
|
|
||||||
|
:param dict connection_info: The connection for the extended volume.
|
||||||
|
:param nova.objects.instance.Instance instance:
|
||||||
|
The instance whose volume gets extended.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
vol_drv = vol_attach.build_volume_driver(
|
vol_drv = vol_attach.build_volume_driver(
|
||||||
self.adapter, self.host_uuid, instance, connection_info)
|
self.adapter, self.host_uuid, instance, connection_info)
|
||||||
vol_drv.extend_volume()
|
vol_drv.extend_volume()
|
||||||
|
@ -764,6 +770,9 @@ class PowerVMDriver(driver.ComputeDriver):
|
||||||
"""Detach the volume attached to the instance."""
|
"""Detach the volume attached to the instance."""
|
||||||
self._log_operation('detach_volume', instance)
|
self._log_operation('detach_volume', instance)
|
||||||
|
|
||||||
|
# Define the flow
|
||||||
|
flow = tf_lf.Flow("detach_volume")
|
||||||
|
|
||||||
# Get a volume adapter for this volume
|
# Get a volume adapter for this volume
|
||||||
vol_drv = vol_attach.build_volume_driver(
|
vol_drv = vol_attach.build_volume_driver(
|
||||||
self.adapter, self.host_uuid, instance, connection_info)
|
self.adapter, self.host_uuid, instance, connection_info)
|
||||||
|
@ -783,9 +792,6 @@ class PowerVMDriver(driver.ComputeDriver):
|
||||||
mig.cleanup_volume(vol_drv)
|
mig.cleanup_volume(vol_drv)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Define the flow
|
|
||||||
flow = tf_lf.Flow("detach_volume")
|
|
||||||
|
|
||||||
# Add a task to detach the volume
|
# Add a task to detach the volume
|
||||||
slot_mgr = slot.build_slot_mgr(instance, self.store_api)
|
slot_mgr = slot.build_slot_mgr(instance, self.store_api)
|
||||||
flow.add(tf_stg.DisconnectVolume(vol_drv, slot_mgr))
|
flow.add(tf_stg.DisconnectVolume(vol_drv, slot_mgr))
|
||||||
|
@ -1660,10 +1666,6 @@ class PowerVMDriver(driver.ComputeDriver):
|
||||||
"""Yields a bdm and volume driver."""
|
"""Yields a bdm and volume driver."""
|
||||||
# Get a volume driver for each volume
|
# Get a volume driver for each volume
|
||||||
for bdm in bdms or []:
|
for bdm in bdms or []:
|
||||||
# Ignore if it's not a volume
|
|
||||||
if not bdm.is_volume:
|
|
||||||
continue
|
|
||||||
|
|
||||||
vol_drv = vol_attach.build_volume_driver(
|
vol_drv = vol_attach.build_volume_driver(
|
||||||
self.adapter, self.host_uuid, instance,
|
self.adapter, self.host_uuid, instance,
|
||||||
bdm.get('connection_info'), stg_ftsk=stg_ftsk)
|
bdm.get('connection_info'), stg_ftsk=stg_ftsk)
|
||||||
|
@ -1688,7 +1690,7 @@ class PowerVMDriver(driver.ComputeDriver):
|
||||||
classes from nova.virt.block_device. Each block device
|
classes from nova.virt.block_device. Each block device
|
||||||
represents one volume connection.
|
represents one volume connection.
|
||||||
|
|
||||||
An example string representation of the a DriverVolumeBlockDevice
|
An example string representation of a DriverVolumeBlockDevice
|
||||||
from the early Liberty time frame is:
|
from the early Liberty time frame is:
|
||||||
{'guest_format': None,
|
{'guest_format': None,
|
||||||
'boot_index': 0,
|
'boot_index': 0,
|
||||||
|
|
|
@ -55,8 +55,6 @@ class ConnectVolume(task.Task):
|
||||||
self.vol_drv.connect_volume(self.slot_mgr)
|
self.vol_drv.connect_volume(self.slot_mgr)
|
||||||
|
|
||||||
def revert(self, result, flow_failures):
|
def revert(self, result, flow_failures):
|
||||||
# The parameters have to match the execute method, plus the response +
|
|
||||||
# failures even if only a subset are used.
|
|
||||||
LOG.warning('Rolling back connection for volume %(vol)s.',
|
LOG.warning('Rolling back connection for volume %(vol)s.',
|
||||||
{'vol': self.vol_id}, instance=self.vol_drv.instance)
|
{'vol': self.vol_id}, instance=self.vol_drv.instance)
|
||||||
|
|
||||||
|
@ -101,8 +99,6 @@ class DisconnectVolume(task.Task):
|
||||||
self.vol_drv.disconnect_volume(self.slot_mgr)
|
self.vol_drv.disconnect_volume(self.slot_mgr)
|
||||||
|
|
||||||
def revert(self, result, flow_failures):
|
def revert(self, result, flow_failures):
|
||||||
# The parameters have to match the execute method, plus the response +
|
|
||||||
# failures even if only a subset are used.
|
|
||||||
LOG.warning('Reconnecting volume %(vol)s on disconnect rollback.',
|
LOG.warning('Reconnecting volume %(vol)s on disconnect rollback.',
|
||||||
{'vol': self.vol_id}, instance=self.vol_drv.instance)
|
{'vol': self.vol_id}, instance=self.vol_drv.instance)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2015, 2018 IBM Corp.
|
# Copyright IBM Corp. and contributors
|
||||||
#
|
#
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
|
@ -152,8 +152,10 @@ class VscsiVolumeAdapter(object):
|
||||||
:param tag: String tag to set on the physical volume.
|
:param tag: String tag to set on the physical volume.
|
||||||
"""
|
"""
|
||||||
def add_func(vios_w):
|
def add_func(vios_w):
|
||||||
LOG.info("Adding vSCSI mapping to Physical Volume %(dev)s",
|
LOG.info("Adding vSCSI mapping to Physical Volume %(dev)s on "
|
||||||
{'dev': device_name}, instance=self.instance)
|
"vios %(vios)s.",
|
||||||
|
{'dev': device_name, 'vios': vios_w.name},
|
||||||
|
instance=self.instance)
|
||||||
pv = pvm_stor.PV.bld(self.adapter, device_name, udid=udid,
|
pv = pvm_stor.PV.bld(self.adapter, device_name, udid=udid,
|
||||||
tag=tag)
|
tag=tag)
|
||||||
v_map = tsk_map.build_vscsi_mapping(
|
v_map = tsk_map.build_vscsi_mapping(
|
||||||
|
@ -172,8 +174,8 @@ class VscsiVolumeAdapter(object):
|
||||||
except (KeyError, ValueError):
|
except (KeyError, ValueError):
|
||||||
# It's common to lose our specific data in the BDM. The connection
|
# It's common to lose our specific data in the BDM. The connection
|
||||||
# information can be 'refreshed' by operations like LPM and resize
|
# information can be 'refreshed' by operations like LPM and resize
|
||||||
LOG.info('Failed to retrieve device_id key from BDM for volume id '
|
LOG.info('Failed to retrieve target_UDID key from BDM for volume '
|
||||||
'%s', self.volume_id, instance=self.instance)
|
'id %s', self.volume_id, instance=self.instance)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _set_udid(self, udid):
|
def _set_udid(self, udid):
|
||||||
|
@ -184,7 +186,7 @@ class VscsiVolumeAdapter(object):
|
||||||
self.connection_info['data'][UDID_KEY] = udid
|
self.connection_info['data'][UDID_KEY] = udid
|
||||||
|
|
||||||
def _add_remove_mapping(self, vm_uuid, vios_uuid, device_name, slot_mgr):
|
def _add_remove_mapping(self, vm_uuid, vios_uuid, device_name, slot_mgr):
|
||||||
"""Adds a transaction to remove the storage mapping.
|
"""Adds a subtask to remove the storage mapping.
|
||||||
|
|
||||||
:param vm_uuid: The UUID of the VM instance
|
:param vm_uuid: The UUID of the VM instance
|
||||||
:param vios_uuid: The UUID of the vios for the pypowervm adapter.
|
:param vios_uuid: The UUID of the vios for the pypowervm adapter.
|
||||||
|
@ -193,8 +195,10 @@ class VscsiVolumeAdapter(object):
|
||||||
used when a volume is detached from the VM.
|
used when a volume is detached from the VM.
|
||||||
"""
|
"""
|
||||||
def rm_func(vios_w):
|
def rm_func(vios_w):
|
||||||
LOG.info("Removing vSCSI mapping from physical volume %(dev)s.",
|
LOG.info("Removing vSCSI mapping from physical volume %(dev)s "
|
||||||
{'dev': device_name}, instance=self.instance)
|
"on vios %(vios)s",
|
||||||
|
{'dev': device_name, 'vios': vios_w.name},
|
||||||
|
instance=self.instance)
|
||||||
removed_maps = tsk_map.remove_maps(
|
removed_maps = tsk_map.remove_maps(
|
||||||
vios_w, vm_uuid,
|
vios_w, vm_uuid,
|
||||||
tsk_map.gen_match_func(pvm_stor.PV, names=[device_name]))
|
tsk_map.gen_match_func(pvm_stor.PV, names=[device_name]))
|
||||||
|
@ -249,7 +253,7 @@ class VscsiVolumeAdapter(object):
|
||||||
from.
|
from.
|
||||||
:param device_name: The hdisk name to remove.
|
:param device_name: The hdisk name to remove.
|
||||||
|
|
||||||
:return: True is there are multiple instances using the given hdisk
|
:return: True if there are multiple instances using the given hdisk
|
||||||
"""
|
"""
|
||||||
vios_scsi_mappings = next(v.scsi_mappings for v in self.stg_ftsk.feed
|
vios_scsi_mappings = next(v.scsi_mappings for v in self.stg_ftsk.feed
|
||||||
if v.uuid == vios_wrap.uuid)
|
if v.uuid == vios_wrap.uuid)
|
||||||
|
@ -257,11 +261,10 @@ class VscsiVolumeAdapter(object):
|
||||||
vios_scsi_mappings, None,
|
vios_scsi_mappings, None,
|
||||||
tsk_map.gen_match_func(pvm_stor.PV, names=[device_name]))
|
tsk_map.gen_match_func(pvm_stor.PV, names=[device_name]))
|
||||||
|
|
||||||
LOG.info("%(num)d storage mappings found for %(dev)s on VIOS %(vios)s",
|
LOG.debug("%(num)d storage mapping(s) found for %(dev)s on VIOS "
|
||||||
{'num': len(mappings), 'dev': device_name,
|
"%(vios)s", {'num': len(mappings), 'dev': device_name,
|
||||||
'vios': vios_wrap.name}, instance=self.instance)
|
'vios': vios_wrap.name}, instance=self.instance)
|
||||||
# the mapping is still present as the task feed removes
|
# the mapping is still present as the task feed removes it later
|
||||||
# the mapping later
|
|
||||||
return len(mappings) > 1
|
return len(mappings) > 1
|
||||||
|
|
||||||
def _cleanup_volume(self, udid=None, devname=None):
|
def _cleanup_volume(self, udid=None, devname=None):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2015, 2018 IBM Corp.
|
# Copyright IBM Corp. and contributors
|
||||||
#
|
#
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
|
@ -175,7 +175,7 @@ class PVVscsiFCVolumeAdapter(volume.VscsiVolumeAdapter,
|
||||||
:param volume_id: Volume to discover
|
:param volume_id: Volume to discover
|
||||||
:returns: Status of the volume or None
|
:returns: Status of the volume or None
|
||||||
:returns: Device name or None
|
:returns: Device name or None
|
||||||
:returns: LUN or None
|
:returns: UDID or None
|
||||||
"""
|
"""
|
||||||
# Get the initiatior WWPNs, targets and Lun for the given VIOS.
|
# Get the initiatior WWPNs, targets and Lun for the given VIOS.
|
||||||
vio_wwpns, t_wwpns, lun = self._get_hdisk_itls(vios_w)
|
vio_wwpns, t_wwpns, lun = self._get_hdisk_itls(vios_w)
|
||||||
|
@ -196,13 +196,13 @@ class PVVscsiFCVolumeAdapter(volume.VscsiVolumeAdapter,
|
||||||
LOG.info('Discovered %(hdisk)s on vios %(vios)s for volume '
|
LOG.info('Discovered %(hdisk)s on vios %(vios)s for volume '
|
||||||
'%(volume_id)s. Status code: %(status)s.',
|
'%(volume_id)s. Status code: %(status)s.',
|
||||||
{'hdisk': device_name, 'vios': vios_w.name,
|
{'hdisk': device_name, 'vios': vios_w.name,
|
||||||
'volume_id': volume_id, 'status': str(status)},
|
'volume_id': volume_id, 'status': status},
|
||||||
instance=self.instance)
|
instance=self.instance)
|
||||||
elif status == hdisk.LUAStatus.DEVICE_IN_USE:
|
elif status == hdisk.LUAStatus.DEVICE_IN_USE:
|
||||||
LOG.warning('Discovered device %(dev)s for volume %(volume)s '
|
LOG.warning('Discovered device %(dev)s for volume %(volume)s '
|
||||||
'on %(vios)s is in use. Error code: %(status)s.',
|
'on %(vios)s is in use. Error code: %(status)s.',
|
||||||
{'dev': device_name, 'volume': volume_id,
|
{'dev': device_name, 'volume': volume_id,
|
||||||
'vios': vios_w.name, 'status': str(status)},
|
'vios': vios_w.name, 'status': status},
|
||||||
instance=self.instance)
|
instance=self.instance)
|
||||||
|
|
||||||
return status, device_name, udid
|
return status, device_name, udid
|
||||||
|
@ -243,7 +243,9 @@ class PVVscsiFCVolumeAdapter(volume.VscsiVolumeAdapter,
|
||||||
# Save the UDID for the disk in the connection info. It is
|
# Save the UDID for the disk in the connection info. It is
|
||||||
# used for the detach.
|
# used for the detach.
|
||||||
self._set_udid(udid)
|
self._set_udid(udid)
|
||||||
LOG.debug('Added deferred task to attach device %s', device_name,
|
LOG.debug('Added deferred task to attach device %(device_name)s '
|
||||||
|
'to vios %(vios_name)s.',
|
||||||
|
{'device_name': device_name, 'vios_name': vios_w.name},
|
||||||
instance=self.instance)
|
instance=self.instance)
|
||||||
|
|
||||||
# Valid attachment
|
# Valid attachment
|
||||||
|
@ -267,10 +269,9 @@ class PVVscsiFCVolumeAdapter(volume.VscsiVolumeAdapter,
|
||||||
LOG.debug("Disconnect volume %(vol)s from vios uuid %(uuid)s",
|
LOG.debug("Disconnect volume %(vol)s from vios uuid %(uuid)s",
|
||||||
dict(vol=self.volume_id, uuid=vios_w.uuid),
|
dict(vol=self.volume_id, uuid=vios_w.uuid),
|
||||||
instance=self.instance)
|
instance=self.instance)
|
||||||
udid, device_name = None, None
|
device_name = None
|
||||||
|
udid = self._get_udid()
|
||||||
try:
|
try:
|
||||||
udid = self._get_udid()
|
|
||||||
|
|
||||||
if udid:
|
if udid:
|
||||||
# This will only work if vios_w has the Storage XAG.
|
# This will only work if vios_w has the Storage XAG.
|
||||||
device_name = vios_w.hdisk_from_uuid(udid)
|
device_name = vios_w.hdisk_from_uuid(udid)
|
||||||
|
@ -280,10 +281,8 @@ class PVVscsiFCVolumeAdapter(volume.VscsiVolumeAdapter,
|
||||||
status, device_name, udid = self._discover_volume_on_vios(
|
status, device_name, udid = self._discover_volume_on_vios(
|
||||||
vios_w, self.volume_id)
|
vios_w, self.volume_id)
|
||||||
|
|
||||||
# If we have a device name, but not a udid, at this point
|
# Check if the hdisk is in a bad state in the I/O Server.
|
||||||
# we should not continue. The hdisk is in a bad state
|
# Subsequent scrub code on future deploys will clean it up.
|
||||||
# in the I/O Server. Subsequent scrub code on future
|
|
||||||
# deploys will clean this up.
|
|
||||||
if not hdisk.good_discovery(status, device_name):
|
if not hdisk.good_discovery(status, device_name):
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
"Disconnect Volume: The backing hdisk for volume "
|
"Disconnect Volume: The backing hdisk for volume "
|
||||||
|
@ -299,8 +298,8 @@ class PVVscsiFCVolumeAdapter(volume.VscsiVolumeAdapter,
|
||||||
"Disconnect Volume: Failed to find disk on Virtual I/O "
|
"Disconnect Volume: Failed to find disk on Virtual I/O "
|
||||||
"Server %(vios_name)s for volume %(volume_id)s. Volume "
|
"Server %(vios_name)s for volume %(volume_id)s. Volume "
|
||||||
"UDID: %(volume_uid)s.",
|
"UDID: %(volume_uid)s.",
|
||||||
{'volume_uid': udid, 'vios_name': vios_w.name,
|
{'vios_name': vios_w.name, 'volume_id': self.volume_id,
|
||||||
'volume_id': self.volume_id}, instance=self.instance)
|
'volume_uid': udid}, instance=self.instance)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# We have found the device name
|
# We have found the device name
|
||||||
|
|
Loading…
Reference in New Issue