From fc628957d03365552dbf094ca143d3ae998ed154 Mon Sep 17 00:00:00 2001 From: Chris M Date: Sun, 21 Jul 2019 18:54:11 +0000 Subject: [PATCH] Fix dothill multiattach support Report multiattach support correctly, and avoid attempts to mount a volume more than once to the same host. Change-Id: Ibff3dda47d0891606e07187624dde700b01eb869 --- .../tests/unit/volume/drivers/test_dothill.py | 4 +-- .../volume/drivers/dothill/dothill_client.py | 26 +++++++++++++++++++ .../volume/drivers/dothill/dothill_common.py | 3 +-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/cinder/tests/unit/volume/drivers/test_dothill.py b/cinder/tests/unit/volume/drivers/test_dothill.py index 77ebc581e8b..02cabe12887 100644 --- a/cinder/tests/unit/volume/drivers/test_dothill.py +++ b/cinder/tests/unit/volume/drivers/test_dothill.py @@ -400,6 +400,7 @@ class TestFCDotHillCommon(test.TestCase): self.assertIsNone(ret) self.assertEqual({'driver_version': self.common.VERSION, 'pools': [{'QoS_support': False, + 'multiattach': True, 'free_capacity_gb': 90, 'location_info': 'DotHillVolumeDriver:xxxxx:OpenStack:A', @@ -407,7 +408,6 @@ class TestFCDotHillCommon(test.TestCase): 'total_capacity_gb': 100}], 'storage_protocol': None, 'vendor_name': 'DotHill', - 'multiattach': True, 'volume_backend_name': None}, self.common.stats) @mock.patch.object(dothill.DotHillClient, 'create_volume') @@ -716,11 +716,11 @@ class TestDotHillFC(test.TestCase): 'driver_version': self.driver.VERSION, 'volume_backend_name': None, 'vendor_name': self.vendor_name, - 'multiattach': True, 'pools': [{'free_capacity_gb': 90, 'reserved_percentage': 0, 'total_capacity_gb': 100, 'QoS_support': False, + 'multiattach': True, 'location_info': 'xx:xx:xx:xx', 'pool_name': 'x'}]} mock_stats.side_effect = [exception.Invalid, stats, stats] diff --git a/cinder/volume/drivers/dothill/dothill_client.py b/cinder/volume/drivers/dothill/dothill_client.py index 1a1a3e9e166..7a14fc1bd9b 100644 --- a/cinder/volume/drivers/dothill/dothill_client.py +++ b/cinder/volume/drivers/dothill/dothill_client.py @@ -23,6 +23,7 @@ from defusedxml import lxml as etree from oslo_log import log as logging from oslo_utils import strutils from oslo_utils import units +import pprint import requests import six @@ -380,8 +381,33 @@ class DotHillClient(object): raise dh_exception.DotHillRequestError( message=_("No LUNs available for mapping to host %s.") % host) + def _is_mapped(self, volume_name, ids): + if not isinstance(ids, list): + ids = [ids] + try: + xml = self._request('/show/volume-maps', volume_name) + + for obj in xml.xpath("//OBJECT[@basetype='volume-view-mappings']"): + lun = obj.findtext("PROPERTY[@name='lun']") + iid = obj.findtext("PROPERTY[@name='identifier']") + if iid in ids: + LOG.debug("volume '{}' is already mapped to {} at lun {}". + format(volume_name, iid, lun)) + return lun + except Exception as e: + LOG.exception("failed to look up mappings for volume '%s'", + volume_name) + raise + return None + @coordination.synchronized('{self._driver_name}-{self._array_name}-map') def map_volume(self, volume_name, connector, connector_element): + # If multiattach enabled, its possible the volume is already mapped + LOG.debug("map_volume(%s, %s, %s)", volume_name, + pprint.pformat(connector), connector_element) + lun = self._is_mapped(volume_name, connector[connector_element]) + if lun: + return lun if connector_element == 'wwpns': lun = self._get_first_available_lun_for_host(connector['wwpns'][0]) host = ",".join(connector['wwpns']) diff --git a/cinder/volume/drivers/dothill/dothill_common.py b/cinder/volume/drivers/dothill/dothill_common.py index bca02950e14..4e96f9d93ee 100644 --- a/cinder/volume/drivers/dothill/dothill_common.py +++ b/cinder/volume/drivers/dothill/dothill_common.py @@ -264,10 +264,9 @@ class DotHillCommon(object): 'storage_protocol': None, 'vendor_name': self.vendor_name, 'volume_backend_name': None, - 'multiattach': True, 'pools': []} - pool = {'QoS_support': False} + pool = {'QoS_support': False, 'multiattach': True} try: src_type = "%sVolumeDriver" % self.vendor_name backend_stats = self.client.backend_stats(self.backend_name,