diff --git a/cinder-powervc/powervc/volume/driver/powervc.py b/cinder-powervc/powervc/volume/driver/powervc.py index 7b52356..05e2b3d 100644 --- a/cinder-powervc/powervc/volume/driver/powervc.py +++ b/cinder-powervc/powervc/volume/driver/powervc.py @@ -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) + diff --git a/cinder-powervc/powervc/volume/driver/service.py b/cinder-powervc/powervc/volume/driver/service.py index 5064ba4..b6b0a27 100644 --- a/cinder-powervc/powervc/volume/driver/service.py +++ b/cinder-powervc/powervc/volume/driver/service.py @@ -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) diff --git a/cinder-powervc/powervc/volume/manager/constants.py b/cinder-powervc/powervc/volume/manager/constants.py index f8ffea4..54543af 100644 --- a/cinder-powervc/powervc/volume/manager/constants.py +++ b/cinder-powervc/powervc/volume/manager/constants.py @@ -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" diff --git a/cinder-powervc/powervc/volume/manager/manager.py b/cinder-powervc/powervc/volume/manager/manager.py index c6edf41..c5a261c 100644 --- a/cinder-powervc/powervc/volume/manager/manager.py +++ b/cinder-powervc/powervc/volume/manager/manager.py @@ -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') diff --git a/nova-powervc/powervc/nova/driver/virt/powervc/service.py b/nova-powervc/powervc/nova/driver/virt/powervc/service.py index 0974f91..352f838 100644 --- a/nova-powervc/powervc/nova/driver/virt/powervc/service.py +++ b/nova-powervc/powervc/nova/driver/virt/powervc/service.py @@ -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