Complete volume attachment until volume become to 'in-use'
1. Move the wait volume state logic from nova to cinder 2. Wait volume state to be "in-use", then complete volume attachment 3. Change volume sync code to not sync "attaching" or "detaching" state as if sync code change such state, then volume attach/detach will be broken Closes-Bug: #1402467 Change-Id: I3640afe9ad4aba8788a932d05e94f55a3b8d6333
This commit is contained in:
parent
3699879307
commit
9b9d3d05a7
|
@ -1,5 +1,5 @@
|
|||
from __future__ import absolute_import
|
||||
# Copyright 2013 IBM Corp.
|
||||
# Copyright 2013, 2014 IBM Corp.
|
||||
import logging
|
||||
import sys
|
||||
|
||||
|
@ -301,3 +301,16 @@ class PowerVCDriver(VolumeDriver):
|
|||
return name
|
||||
else:
|
||||
return volume.id
|
||||
|
||||
def attach_volume(self, context, volume, instance_uuid, host_name,
|
||||
mountpoint):
|
||||
"""Callback for volume attached to instance or host."""
|
||||
# wait for volume to be attached
|
||||
self._service.attach_volume(context, volume, instance_uuid, host_name,
|
||||
mountpoint)
|
||||
|
||||
def detach_volume(self, context, volume):
|
||||
"""Callback for volume detached."""
|
||||
# wait for volume to be detached
|
||||
self._service.detach_volume(context, volume)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from __future__ import absolute_import
|
||||
# Copyright 2013 IBM Corp.
|
||||
# Copyright 2013, 2014 IBM Corp.
|
||||
|
||||
import httplib
|
||||
|
||||
|
@ -270,3 +270,62 @@ class PowerVCService(object):
|
|||
|
||||
def list_storage_providers(self):
|
||||
return PowerVCService._client.storage_providers.list()
|
||||
|
||||
def attach_volume(self, context, volume, instance_uuid, host_name,
|
||||
mountpoint):
|
||||
"""Callback for volume attached to instance or host."""
|
||||
# wait for volume to be attached, the volume-attach operation is done
|
||||
# in nova
|
||||
pvc_volume_id = None
|
||||
for metaDataItem in volume.volume_metadata:
|
||||
if metaDataItem.key == constants.LOCAL_PVC_PREFIX + 'id':
|
||||
pvc_volume_id = metaDataItem.value
|
||||
break
|
||||
else:
|
||||
LOG.warning('Fail to get pvc_id %s' % volume_id)
|
||||
raise exceptions.BadRequest
|
||||
|
||||
LOG.debug('wait until PVC volume %s status to in-use', pvc_volume_id)
|
||||
FILPC = loopingcall.FixedIntervalLoopingCall
|
||||
timer = FILPC(self._wait_for_state_change,
|
||||
pvc_volume_id,
|
||||
constants.STATUS_AVAILABLE,
|
||||
constants.STATUS_INUSE,
|
||||
constants.STATUS_ATTACHING)
|
||||
|
||||
try:
|
||||
timer.start(interval=10).wait()
|
||||
except:
|
||||
LOG.error("volume %s attaching failed, ", volume.id)
|
||||
# when attached failed raise exception
|
||||
raise exception.CinderException('Volume %s attaching failed',
|
||||
volume.id)
|
||||
|
||||
def detach_volume(self, context, volume):
|
||||
"""Callback for volume detach to instance or host."""
|
||||
# wait for volume to be detached, the volume-detach operation is done
|
||||
# in nova
|
||||
pvc_volume_id = None
|
||||
for metaDataItem in volume.volume_metadata:
|
||||
if metaDataItem.key == constants.LOCAL_PVC_PREFIX + 'id':
|
||||
pvc_volume_id = metaDataItem.value
|
||||
break
|
||||
else:
|
||||
LOG.warning('Fail to get pvc_id %s' % volume_id)
|
||||
raise exceptions.BadRequest
|
||||
|
||||
LOG.debug('wait until PVC volume %s status to available', pvc_volume_id)
|
||||
FILPC = loopingcall.FixedIntervalLoopingCall
|
||||
timer = FILPC(self._wait_for_state_change,
|
||||
pvc_volume_id,
|
||||
constants.STATUS_INUSE,
|
||||
constants.STATUS_AVAILABLE,
|
||||
constants.STATUS_DETACHING)
|
||||
|
||||
try:
|
||||
timer.start(interval=10).wait()
|
||||
except:
|
||||
LOG.error("volume %s detaching failed, ", volume.id)
|
||||
# when attached failed raise exception
|
||||
raise exception.CinderException('Volume %s detaching failed',
|
||||
volume.id)
|
||||
|
|
|
@ -52,6 +52,9 @@ STATUS_AVAILABLE = 'available'
|
|||
STATUS_ERROR = 'error'
|
||||
STATUS_CREATING = 'creating'
|
||||
STATUS_DELETING = 'deleting'
|
||||
STATUS_INUSE = 'in-use'
|
||||
STATUS_ATTACHING = 'attaching'
|
||||
STATUS_DETACHING = 'detaching'
|
||||
|
||||
# multi-backends configuration option for PowerVCDriver
|
||||
BACKEND_POWERVCDRIVER = "powervcdriver"
|
||||
|
|
|
@ -938,6 +938,19 @@ class PowerVCCinderManager(service.Service):
|
|||
|
||||
return found
|
||||
|
||||
def _is_intermediate_state(self, local_volume=None, pvc_volume=None):
|
||||
intermediate_statuses = [constants.STATUS_ATTACHING,
|
||||
constants.STATUS_DETACHING]
|
||||
if local_volume:
|
||||
local_volume_state = local_volume.get('status')
|
||||
if local_volume_state in intermediate_statuses:
|
||||
return True
|
||||
if pvc_volume:
|
||||
pvc_volume_state = pvc_volume.get('status')
|
||||
if pvc_volume_state in intermediate_statuses:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _sync_existing_volume(self, context, local_volume, pvc_volume):
|
||||
ret = False
|
||||
if local_volume is None or pvc_volume is None:
|
||||
|
@ -949,6 +962,12 @@ class PowerVCCinderManager(service.Service):
|
|||
" Skipping volume sync."))
|
||||
return ret
|
||||
|
||||
if self._is_intermediate_state(local_volume, pvc_volume):
|
||||
LOG.info('volume can not be synced as local or pvc volume state in'
|
||||
'intermediate state: %s, '
|
||||
'%s' % (local_volume.get('status'), pvc_volume))
|
||||
return
|
||||
|
||||
values = self._get_values_from_volume(context,
|
||||
pvc_volume,
|
||||
local_volume)
|
||||
|
@ -992,6 +1011,10 @@ class PowerVCCinderManager(service.Service):
|
|||
LOG.debug("Volume is None, cannot insert it")
|
||||
return
|
||||
|
||||
if self._is_intermediate_state(pvc_volume=volume):
|
||||
LOG.info('pvc volume is in a intermediate status, ignore to insert:'
|
||||
' %s' % volume)
|
||||
return
|
||||
volume_info = volume
|
||||
volume_type = volume_info.get('volume_type')
|
||||
volume_display_name = volume_info.get('display_name')
|
||||
|
|
|
@ -427,38 +427,6 @@ class PowerVCService(object):
|
|||
LOG.warning(_("VolumeId missing in detaching volume"))
|
||||
self._volumes.delete_server_volume(server_id, volume_id)
|
||||
|
||||
def _wait_for_detach(server_id, volume_id):
|
||||
"""
|
||||
This method is used to call at an interval until the volume is
|
||||
detached from the server.
|
||||
"""
|
||||
try:
|
||||
volume = self._volumes.get_server_volume(server_id, volume_id)
|
||||
except exceptions.NotFound:
|
||||
LOG.info(
|
||||
_("Detach the volume on instance %s successfully.")
|
||||
% server_id)
|
||||
raise loopingcall.LoopingCallDone(True)
|
||||
|
||||
if volume:
|
||||
if self.try_time > self.max_tries:
|
||||
LOG.info(_("Volume %s failed to detach.") % volume_id)
|
||||
# There is no VolumeDetachFailed like exception defined
|
||||
raise loopingcall.LoopingCallDone(True)
|
||||
else:
|
||||
LOG.debug(_("Looping call to check detach of volume %s.")
|
||||
% volume_id)
|
||||
self.try_time += 1
|
||||
else:
|
||||
raise loopingcall.LoopingCallDone(True)
|
||||
|
||||
self.try_time = 0
|
||||
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_detach,
|
||||
server_id,
|
||||
volume_id)
|
||||
return timer.start(self.longrun_loop_interval,
|
||||
self.longrun_initial_delay).wait()
|
||||
|
||||
def power_off(self, instance):
|
||||
"""Power off the specified instance."""
|
||||
server_instance = self._get_server(instance)
|
||||
|
@ -1056,15 +1024,6 @@ class PowerVCService(object):
|
|||
volume_id,
|
||||
mountpoint)
|
||||
|
||||
self.try_time = 0
|
||||
timer = loopingcall.\
|
||||
FixedIntervalLoopingCall(self._check_attachment_of_instance,
|
||||
server_id,
|
||||
volume_id)
|
||||
|
||||
return timer.start(self.longrun_loop_interval,
|
||||
self.longrun_initial_delay).wait()
|
||||
|
||||
def list_attachments_of_instance(self, server_id):
|
||||
"""
|
||||
Lists the volume attachments for the specified server.
|
||||
|
@ -1074,30 +1033,6 @@ class PowerVCService(object):
|
|||
|
||||
return response
|
||||
|
||||
def _check_attachment_of_instance(self, server_id, volume_id):
|
||||
"""
|
||||
Check whether the specified volume has been attached to
|
||||
the specified instance.
|
||||
"""
|
||||
self.try_time = self.try_time + 1
|
||||
try:
|
||||
attachments = self.list_attachments_of_instance(server_id)
|
||||
except exceptions:
|
||||
LOG.warning(_("Fail to get the attachments of the server:\
|
||||
VM %s.") % server_id)
|
||||
raise exceptions.BadRequest
|
||||
|
||||
for attachment in attachments:
|
||||
get_volume_id = getattr(attachment, 'volumeId', '')
|
||||
|
||||
if get_volume_id == volume_id:
|
||||
LOG.debug(_("The attach_volume operation of the server:\
|
||||
VM %s is completed") % server_id)
|
||||
raise loopingcall.LoopingCallDone(True)
|
||||
|
||||
if self.try_time > self.max_tries:
|
||||
raise exception.VolumeUnattached
|
||||
|
||||
def _get_pvc_volume_id(self, local_id):
|
||||
"""
|
||||
The method get_pvc_volume_id is used to get the PowerVC volume id
|
||||
|
|
Loading…
Reference in New Issue