Update tgt iSCSI target on volume extend

When extending an in-use volume, the volume will be extended but
the target exposing the volume will still report the original size.

The target needs to be updated to pick up the change, but since it
is in-use the update must be forced. This can cause IO disruption
if there is active IO to the target, however retries will cause the
next attempt to succeed and there will just be a few second IO
pause on the host while the target session is reestablished. Not
ideal, but it does recover with minimal impact on the host.

And operators probably shouldn't extend volumes without pausing
active IO to the volume anyway.

See bug report comments for more testing details. Marking this as
partial as it only addresses the tgt target and further
investigation is needed to see if the other target drivers need
similar updates.

Change-Id: I0f7b58751c6d8d05cad5b1b95c4e21c8b5d36692
Partial-bug: #1731984
This commit is contained in:
Sean McGinnis 2017-12-21 02:04:25 -06:00
parent f8080f053a
commit d96b6dfba0
5 changed files with 33 additions and 3 deletions

View File

@ -1154,6 +1154,10 @@ class ISCSITargetDetachFailed(CinderException):
message = _("Failed to detach iSCSI target for volume %(volume_id)s.")
class TargetUpdateFailed(CinderException):
message = _("Failed to update target for volume %(volume_id)s.")
class ISCSITargetHelperCommandFailed(CinderException):
message = "%(error_message)s"

View File

@ -589,6 +589,11 @@ class LVMVolumeDriver(driver.VolumeDriver):
"""Extend an existing volume's size."""
self.vg.extend_volume(volume['name'],
self._sizestr(new_size))
try:
self.target_driver.extend_target(volume)
except Exception:
LOG.exception('Error extending target after volume resize.')
raise exception.TargetUpdateFailed(volume_id=volume.id)
def manage_existing(self, volume, existing_ref):
"""Manages an existing LV.

View File

@ -2591,6 +2591,9 @@ class VolumeManager(manager.CleanableManager,
self._notify_about_volume_usage(context, volume, "resize.start")
try:
self.driver.extend_volume(volume, new_size)
except exception.TargetUpdateFailed:
# We just want to log this but continue on with quota commit
LOG.warning('Volume extended but failed to update target.')
except Exception:
LOG.exception("Extend volume failed.",
resource=volume)

View File

@ -327,6 +327,17 @@ class ISCSITarget(driver.Target):
except exception.NotFound:
LOG.debug('Failed to get CHAP auth from DB for %s.', volume['id'])
def extend_target(self, volume):
"""Reinitializes a target after the LV has been extended.
Note: This will cause IO disruption in most cases.
"""
iscsi_name = "%s%s" % (self.configuration.target_prefix,
volume['name'])
if volume.volume_attachment:
self._do_tgt_update(iscsi_name, force=True)
@abc.abstractmethod
def _get_target_and_lun(self, context, volume):
"""Get iscsi target and lun."""
@ -349,6 +360,9 @@ class ISCSITarget(driver.Target):
def _get_target(self, iqn):
pass
def _do_tgt_update(self, name, force=False):
pass
class SanISCSITarget(ISCSITarget):
"""iSCSI target for san devices.

View File

@ -111,9 +111,13 @@ class TgtAdm(iscsi.ISCSITarget):
return iscsi_target, lun
@utils.retry(putils.ProcessExecutionError)
def _do_tgt_update(self, name):
(out, err) = utils.execute('tgt-admin', '--update', name,
run_as_root=True)
def _do_tgt_update(self, name, force=False):
args = ['tgt-admin', '--update', name]
if force:
# Note: force may fail if there is active IO, but retry decorator
# should allow it to succeed on second attempt
args.append('-f')
(out, err) = utils.execute(*args, run_as_root=True)
LOG.debug("StdOut from tgt-admin --update: %s", out)
LOG.debug("StdErr from tgt-admin --update: %s", err)