From 32bac00ea003015add0d33be262cb3002e4c43af Mon Sep 17 00:00:00 2001 From: "Walter A. Boring IV" Date: Mon, 28 Apr 2014 14:30:47 -0700 Subject: [PATCH] Fixed 3PAR driver issue finding correct vlun This patch fixes an issue that happens when a volume is attached to the same host more than once. The driver wasn't looking for the correct VLUN on the 3par after the VLUN was created. We now get the VLUN information in the return of the creation call. Change-Id: Id570094f29900c0adcffe6c9d4145c9ad5e3ce4e Closes-Bug: #1313894 --- cinder/tests/test_hp3par.py | 12 ++++++ .../volume/drivers/san/hp/hp_3par_common.py | 39 ++++++++++++++----- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/cinder/tests/test_hp3par.py b/cinder/tests/test_hp3par.py index 119f6c4040b..a5d77df86d3 100644 --- a/cinder/tests/test_hp3par.py +++ b/cinder/tests/test_hp3par.py @@ -995,6 +995,12 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase): 'lun': 90, 'type': 0}] mock_client.getPorts.return_value = { 'members': self.FAKE_FC_PORTS + [self.FAKE_ISCSI_PORT]} + location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" % + {'volume_name': self.VOLUME_3PAR_NAME, + 'lun_id': 90, + 'host': self.FAKE_HOST, + 'nsp': 'something'}) + mock_client.createVLUN.return_value = location result = self.driver.initialize_connection(self.volume, self.connector) @@ -1317,6 +1323,12 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase): {'active': True, 'volumeName': self.VOLUME_3PAR_NAME, 'lun': self.TARGET_LUN, 'type': 0}] + location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" % + {'volume_name': self.VOLUME_3PAR_NAME, + 'lun_id': self.TARGET_LUN, + 'host': self.FAKE_HOST, + 'nsp': 'something'}) + mock_client.createVLUN.return_value = location result = self.driver.initialize_connection(self.volume, self.connector) diff --git a/cinder/volume/drivers/san/hp/hp_3par_common.py b/cinder/volume/drivers/san/hp/hp_3par_common.py index 0b55b15658a..b1d188d503b 100644 --- a/cinder/volume/drivers/san/hp/hp_3par_common.py +++ b/cinder/volume/drivers/san/hp/hp_3par_common.py @@ -343,12 +343,26 @@ class HP3PARCommon(object): def _create_3par_vlun(self, volume, hostname, nsp): try: + location = None if nsp is None: - self.client.createVLUN(volume, hostname=hostname, auto=True) + location = self.client.createVLUN(volume, hostname=hostname, + auto=True) else: port = self.build_portPos(nsp) - self.client.createVLUN(volume, hostname=hostname, auto=True, - portPos=port) + location = self.client.createVLUN(volume, hostname=hostname, + auto=True, portPos=port) + + vlun_info = None + if location: + # The LUN id is returned as part of the location URI + vlun = location.split(',') + vlun_info = {'volume_name': vlun[0], + 'lun_id': int(vlun[1]), + 'host_name': vlun[2], + 'nsp': vlun[3], + } + + return vlun_info except hpexceptions.HTTPBadRequest as e: if 'must be in the same domain' in e.get_description(): @@ -452,18 +466,23 @@ class HP3PARCommon(object): 'hp3par_cpg')}) self.stats = stats - def _get_vlun(self, volume_name, hostname): + def _get_vlun(self, volume_name, hostname, lun_id=None): """find a VLUN on a 3PAR host.""" vluns = self.client.getHostVLUNs(hostname) found_vlun = None for vlun in vluns: if volume_name in vlun['volumeName']: - found_vlun = vlun - break + if lun_id: + if vlun['lun'] == lun_id: + found_vlun = vlun + break + else: + found_vlun = vlun + break - msg = (_("3PAR vlun %(name)s not found on host %(host)s") % - {'name': volume_name, 'host': hostname}) if found_vlun is None: + msg = (_("3PAR vlun %(name)s not found on host %(host)s") % + {'name': volume_name, 'host': hostname}) LOG.warn(msg) return found_vlun @@ -473,8 +492,8 @@ class HP3PARCommon(object): In order to export a volume on a 3PAR box, we have to create a VLUN. """ volume_name = self._get_3par_vol_name(volume['id']) - self._create_3par_vlun(volume_name, host['name'], nsp) - return self._get_vlun(volume_name, host['name']) + vlun_info = self._create_3par_vlun(volume_name, host['name'], nsp) + return self._get_vlun(volume_name, host['name'], vlun_info['lun_id']) def delete_vlun(self, volume, hostname): volume_name = self._get_3par_vol_name(volume['id'])