From 245f478d1cba19f04f8a212d26ac8db0f60754b8 Mon Sep 17 00:00:00 2001 From: Kurt Martin Date: Fri, 30 Jan 2015 13:59:56 -0800 Subject: [PATCH] Add dedup provisioning to 3PAR drivers 3PAR now supports thin duplication provisioning. This review is for adding the dedup provisioning support to the 3PAR provisioning extra specs type as well as supporting volume retype between provisioning types (thin<->dedup, full<->dedup). The OpenStack Configuration Reference Guide will need to updated to include dedup as a valid hp3par:provisioning value. A note should also be added that this feature requires SSD disks and 3PAR firmware version 3.2.1 MU1 or greater. DocImpact Implements: blueprint 3par-dedup Change-Id: I6ebad3682d5d53a9b1a6329d666a1d7fb06eba0a --- cinder/tests/test_hp3par.py | 254 ++++++++++++++++-- .../volume/drivers/san/hp/hp_3par_common.py | 96 +++++-- 2 files changed, 305 insertions(+), 45 deletions(-) diff --git a/cinder/tests/test_hp3par.py b/cinder/tests/test_hp3par.py index 8019b767c..af0229654 100644 --- a/cinder/tests/test_hp3par.py +++ b/cinder/tests/test_hp3par.py @@ -69,6 +69,7 @@ class HP3PARBaseDriver(object): VOLUME_ID = 'd03338a9-9115-48a3-8dfc-35cdfcdc15a7' CLONE_ID = 'd03338a9-9115-48a3-8dfc-000000000000' + VOLUME_TYPE_ID_DEDUP = 'd03338a9-9115-48a3-8dfc-11111111111' VOLUME_NAME = 'volume-' + VOLUME_ID VOLUME_NAME_3PAR = 'osv-0DM4qZEVSKON-DXN-NwVpw' SNAPSHOT_ID = '2f823bdc-e36e-4dc8-bd15-de1c7a28ff31' @@ -112,6 +113,14 @@ class HP3PARBaseDriver(object): 'volume_type': None, 'volume_type_id': None} + volume_dedup = {'name': VOLUME_NAME, + 'id': VOLUME_ID, + 'display_name': 'Foo Volume', + 'size': 2, + 'host': FAKE_HOST, + 'volume_type': 'dedup', + 'volume_type_id': VOLUME_TYPE_ID_DEDUP} + volume_pool = {'name': VOLUME_NAME, 'id': VOLUME_ID, 'display_name': 'Foo Volume', @@ -161,6 +170,14 @@ class HP3PARBaseDriver(object): 'deleted_at': None, 'id': 'gold'} + volume_type_dedup = {'name': 'dedup', + 'deleted': False, + 'updated_at': None, + 'extra_specs': {'cpg': HP3PAR_CPG2, + 'provisioning': 'dedup'}, + 'deleted_at': None, + 'id': VOLUME_TYPE_ID_DEDUP} + cpgs = [ {'SAGrowth': {'LDLayout': {'diskPatterns': [{'diskType': 2}]}, 'incrementMiB': 8192}, @@ -250,6 +267,7 @@ class HP3PARBaseDriver(object): 'vvs': RETYPE_VVS_NAME, 'qos': RETYPE_QOS_SPECS, 'tpvv': True, + 'tdvv': False, 'volume_type': volume_type } } @@ -263,6 +281,7 @@ class HP3PARBaseDriver(object): 'vvs': VVS_NAME, 'qos': QOS, 'tpvv': True, + 'tdvv': False, 'volume_type': volume_type } } @@ -276,10 +295,24 @@ class HP3PARBaseDriver(object): 'vvs': RETYPE_VVS_NAME, 'qos': RETYPE_QOS_SPECS, 'tpvv': True, + 'tdvv': False, 'volume_type': volume_type } } + RETYPE_VOLUME_TYPE_3 = { + 'name': 'purple', + 'id': RETYPE_VOLUME_TYPE_ID, + 'extra_specs': { + 'cpg': HP3PAR_CPG_QOS, + 'snap_cpg': HP3PAR_CPG_SNAP, + 'vvs': RETYPE_VVS_NAME, + 'qos': RETYPE_QOS_SPECS, + 'tpvv': False, + 'tdvv': True, + 'volume_type': volume_type + } + } RETYPE_VOLUME_TYPE_BAD_PERSONA = { 'name': 'bad_persona', 'id': 'any_id', @@ -339,6 +372,19 @@ class HP3PARBaseDriver(object): 'comment': RETYPE_TEST_COMMENT } + RETYPE_TEST_COMMENT_2 = "{'retype_test': 'test comment 2'}" + + RETYPE_VOLUME_INFO_2 = { + 'name': VOLUME_NAME, + 'id': VOLUME_ID, + 'display_name': 'Retype Vol2', + 'size': 1, + 'host': RETYPE_HOST, + 'userCPG': HP3PAR_CPG, + 'snapCPG': HP3PAR_CPG_SNAP, + 'provisioningType': 3, + 'comment': RETYPE_TEST_COMMENT + } # Test for when we don't get a snapCPG. RETYPE_VOLUME_INFO_NO_SNAP = { 'name': VOLUME_NAME, @@ -365,6 +411,16 @@ class HP3PARBaseDriver(object): # intentionally removed to make _retype more usable for other use cases. RETYPE_DIFF = None + wsapi_version = {'major': 1, + 'build': 30201120, + 'minor': 4, + 'revision': 1} + + wsapi_version_312 = {'major': 1, + 'build': 30102422, + 'minor': 3, + 'revision': 1} + standard_login = [ mock.call.login(HP3PAR_USER_NAME, HP3PAR_USER_PASS), mock.call.setSSHOptions( @@ -538,6 +594,7 @@ class HP3PARBaseDriver(object): 1907, { 'comment': comment, 'tpvv': True, + 'tdvv': False, 'snapCPG': HP3PAR_CPG_SNAP})] mock_client.assert_has_calls( @@ -566,6 +623,7 @@ class HP3PARBaseDriver(object): 1907, { 'comment': comment, 'tpvv': True, + 'tdvv': False, 'snapCPG': HP3PAR_CPG_SNAP})] mock_client.assert_has_calls( @@ -574,6 +632,30 @@ class HP3PARBaseDriver(object): self.standard_logout) self.assertEqual(return_model, None) + @mock.patch.object(volume_types, 'get_volume_type') + def test_unsupported_dedup_volume_type(self, _mock_volume_types): + + mock_client = self.setup_driver_312() + _mock_volume_types.return_value = { + 'name': 'dedup', + 'extra_specs': { + 'cpg': HP3PAR_CPG_QOS, + 'snap_cpg': HP3PAR_CPG_SNAP, + 'vvs_name': self.VVS_NAME, + 'qos': self.QOS, + 'provisioning': 'dedup', + 'volume_type': self.volume_type_dedup}} + + with mock.patch.object(hpcommon.HP3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + common = self.driver._login() + + self.assertRaises(exception.InvalidInput, + common.get_volume_settings_from_type_id, + self.VOLUME_TYPE_ID_DEDUP, + "mock") + @mock.patch.object(volume_types, 'get_volume_type') def test_get_snap_cpg_from_volume_type(self, _mock_volume_types): @@ -674,6 +756,7 @@ class HP3PARBaseDriver(object): 'vvs_name': self.VVS_NAME, 'qos': self.QOS, 'tpvv': True, + 'tdvv': False, 'volume_type': self.volume_type}} with mock.patch.object(hpcommon.HP3PARCommon, @@ -695,6 +778,55 @@ class HP3PARBaseDriver(object): 1907, { 'comment': comment, 'tpvv': True, + 'tdvv': False, + 'snapCPG': HP3PAR_CPG_SNAP})] + + mock_client.assert_has_calls( + self.standard_login + + expected + + self.standard_logout) + self.assertEqual(return_model, + {'host': volume_utils.append_host( + self.FAKE_HOST, + HP3PAR_CPG_QOS)}) + + @mock.patch.object(volume_types, 'get_volume_type') + def test_create_volume_dedup(self, _mock_volume_types): + # setup_mock_client drive with default configuration + # and return the mock HTTP 3PAR client + mock_client = self.setup_driver() + + _mock_volume_types.return_value = { + 'name': 'dedup', + 'extra_specs': { + 'cpg': HP3PAR_CPG_QOS, + 'snap_cpg': HP3PAR_CPG_SNAP, + 'vvs_name': self.VVS_NAME, + 'qos': self.QOS, + 'provisioning': 'dedup', + 'volume_type': self.volume_type_dedup}} + + with mock.patch.object(hpcommon.HP3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + + return_model = self.driver.create_volume(self.volume_dedup) + comment = ( + '{"volume_type_name": "dedup", "display_name": "Foo Volume"' + ', "name": "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7' + '", "volume_type_id": "d03338a9-9115-48a3-8dfc-11111111111"' + ', "volume_id": "d03338a9-9115-48a3-8dfc-35cdfcdc15a7"' + ', "qos": {}, "type": "OpenStack"}') + + expected = [ + mock.call.getCPG(HP3PAR_CPG_QOS), + mock.call.createVolume( + self.VOLUME_3PAR_NAME, + HP3PAR_CPG_QOS, + 1907, { + 'comment': comment, + 'tpvv': False, + 'tdvv': True, 'snapCPG': HP3PAR_CPG_SNAP})] mock_client.assert_has_calls( @@ -1026,7 +1158,7 @@ class HP3PARBaseDriver(object): "old_type", "old_type_id", HP3PARBaseDriver.RETYPE_HOST, None, cpg, cpg, snap_cpg, snap_cpg, - True, True, None, None, + True, False, False, True, None, None, self.QOS_SPECS, self.RETYPE_QOS_SPECS, "{}") @@ -1044,6 +1176,35 @@ class HP3PARBaseDriver(object): 'osv-0DM4qZEVSKON-DXN-NwVpw')] mock_client.assert_has_calls(expected) + @mock.patch.object(volume_types, 'get_volume_type') + def test_retype_dedup(self, _mock_volume_types): + _mock_volume_types.return_value = self.RETYPE_VOLUME_TYPE_3 + mock_client = self.setup_driver(mock_conf=self.RETYPE_CONF) + + cpg = "any_cpg" + snap_cpg = "any_cpg" + with mock.patch.object(hpcommon.HP3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + common = self.driver._login() + common._retype(self.volume, + HP3PARBaseDriver.VOLUME_3PAR_NAME, + "old_type", "old_type_id", + HP3PARBaseDriver.RETYPE_HOST, + None, cpg, cpg, snap_cpg, snap_cpg, + True, False, False, True, None, None, + self.QOS_SPECS, self.RETYPE_QOS_SPECS, + "{}") + + expected = [ + mock.call.modifyVolume('osv-0DM4qZEVSKON-DXN-NwVpw', + {'action': 6, + 'userCPG': 'any_cpg', + 'conversionOperation': 3, + 'tuneOperation': 1}), + mock.call.getTask(1)] + mock_client.assert_has_calls(expected) + def test_delete_volume(self): # setup_mock_client drive with default configuration # and return the mock HTTP 3PAR client @@ -1086,7 +1247,7 @@ class HP3PARBaseDriver(object): 'osv-0DM4qZEVSKON-AAAAAAAAA', HP3PAR_CPG2, {'snapCPG': 'OpenStackCPGSnap', 'tpvv': True, - 'online': True})] + 'tdvv': False, 'online': True})] mock_client.assert_has_calls( self.standard_login + @@ -1122,7 +1283,7 @@ class HP3PARBaseDriver(object): 'osv-0DM4qZEVSKON-AAAAAAAAA', expected_cpg, {'snapCPG': 'OpenStackCPGSnap', 'tpvv': True, - 'online': True})] + 'tdvv': False, 'online': True})] mock_client.assert_has_calls( self.standard_login + @@ -1565,15 +1726,18 @@ class HP3PARBaseDriver(object): # and return the mock HTTP 3PAR client mock_client = self.setup_driver() - self.driver.create_snapshot(self.snapshot) + with mock.patch.object(hpcommon.HP3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + self.driver.create_snapshot(self.snapshot) - try: - ex = hpexceptions.HTTPNotFound("not found") - mock_client.deleteVolume = mock.Mock(side_effect=ex) - self.driver.delete_snapshot(self.snapshot) - except Exception: - self.fail("Deleting a snapshot that is missing should act as if " - "it worked.") + try: + ex = hpexceptions.HTTPNotFound("not found") + mock_client.deleteVolume = mock.Mock(side_effect=ex) + self.driver.delete_snapshot(self.snapshot) + except Exception: + self.fail("Deleting a snapshot that is missing should act " + "as if it worked.") def test_create_volume_from_snapshot(self): # setup_mock_client drive with default configuration @@ -1687,6 +1851,7 @@ class HP3PARBaseDriver(object): 'vvs_name': self.VVS_NAME, 'qos': self.QOS, 'tpvv': True, + 'tdvv': False, 'volume_type': self.volume_type}} with mock.patch.object(hpcommon.HP3PARCommon, @@ -1745,14 +1910,17 @@ class HP3PARBaseDriver(object): 'getVolume.return_value': {} } - self.setup_driver(mock_conf=conf) + mock_client = self.setup_driver(mock_conf=conf) - volume = self.volume.copy() - volume['size'] = self.volume['size'] + 10 + with mock.patch.object(hpcommon.HP3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + volume = self.volume.copy() + volume['size'] = self.volume['size'] + 10 - self.assertRaises(exception.CinderException, - self.driver.create_volume_from_snapshot, - volume, self.snapshot) + self.assertRaises(exception.CinderException, + self.driver.create_volume_from_snapshot, + volume, self.snapshot) @mock.patch.object(volume_types, 'get_volume_type') def test_create_volume_from_snapshot_qos(self, _mock_volume_types): @@ -1770,6 +1938,7 @@ class HP3PARBaseDriver(object): 'vvs_name': self.VVS_NAME, 'qos': self.QOS, 'tpvv': True, + 'tdvv': False, 'volume_type': self.volume_type}} self.driver.create_volume_from_snapshot( self.volume_qos, @@ -2504,6 +2673,7 @@ class HP3PARBaseDriver(object): 'vvs_name': self.VVS_NAME, 'qos': self.QOS, 'tpvv': True, + 'tdvv': False, 'volume_type': self.volume_type}} volume = {'display_name': None, @@ -2683,6 +2853,28 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase): m_conf=mock_conf, driver=hpfcdriver.HP3PARFCDriver) + mock_client.getWsApiVersion.return_value = self.wsapi_version + + expected = [ + mock.call.getCPG(HP3PAR_CPG), + mock.call.getCPG(HP3PAR_CPG2)] + mock_client.assert_has_calls( + self.standard_login + + expected + + self.standard_logout) + mock_client.reset_mock() + return mock_client + + def setup_driver_312(self, config=None, mock_conf=None): + + self.ctxt = context.get_admin_context() + mock_client = self.setup_mock_client( + conf=config, + m_conf=mock_conf, + driver=hpfcdriver.HP3PARFCDriver) + + mock_client.getWsApiVersion.return_value = self.wsapi_version_312 + expected = [ mock.call.getCPG(HP3PAR_CPG), mock.call.getCPG(HP3PAR_CPG2)] @@ -3326,6 +3518,34 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase): m_conf=mock_conf, driver=hpdriver.HP3PARISCSIDriver) + mock_client.getWsApiVersion.return_value = self.wsapi_version + + expected_get_cpgs = [ + mock.call.getCPG(HP3PAR_CPG), + mock.call.getCPG(HP3PAR_CPG2)] + expected_get_ports = [mock.call.getPorts()] + mock_client.assert_has_calls( + self.standard_login + + expected_get_cpgs + + self.standard_logout + + self.standard_login + + expected_get_ports + + self.standard_logout) + mock_client.reset_mock() + + return mock_client + + def setup_driver_312(self, config=None, mock_conf=None): + + self.ctxt = context.get_admin_context() + + mock_client = self.setup_mock_client( + conf=config, + m_conf=mock_conf, + driver=hpdriver.HP3PARISCSIDriver) + + mock_client.getWsApiVersion.return_value = self.wsapi_version_312 + expected_get_cpgs = [ mock.call.getCPG(HP3PAR_CPG), mock.call.getCPG(HP3PAR_CPG2)] diff --git a/cinder/volume/drivers/san/hp/hp_3par_common.py b/cinder/volume/drivers/san/hp/hp_3par_common.py index 6326e1b86..805cfe752 100644 --- a/cinder/volume/drivers/san/hp/hp_3par_common.py +++ b/cinder/volume/drivers/san/hp/hp_3par_common.py @@ -1,4 +1,4 @@ -# (c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P. +# (c) Copyright 2012-2015 Hewlett-Packard Development Company, L.P. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -69,6 +69,7 @@ from taskflow.patterns import linear_flow LOG = logging.getLogger(__name__) MIN_CLIENT_VERSION = '3.1.2' +DEDUP_API_VERSION = 30201120 hp3par_opts = [ cfg.StrOpt('hp3par_api_url', @@ -164,10 +165,11 @@ class HP3PARCommon(object): 2.0.33 - Fix host persona to match WSAPI mapping bug #1403997 2.0.34 - Fix log messages to match guidelines. bug #1411370 2.0.35 - Fix default snapCPG for manage_existing bug #1393609 + 2.0.36 - Added support for dedup provisioning """ - VERSION = "2.0.35" + VERSION = "2.0.36" stats = {} @@ -179,12 +181,14 @@ class HP3PARCommon(object): VLUN_TYPE_HOST_SET = 5 THIN = 2 + DEDUP = 6 CONVERT_TO_THIN = 1 CONVERT_TO_FULL = 2 + CONVERT_TO_DEDUP = 3 # Valid values for volume type extra specs # The first value in the list is the default value - valid_prov_values = ['thin', 'full'] + valid_prov_values = ['thin', 'full', 'dedup'] valid_persona_values = ['2 - Generic-ALUA', '1 - Generic', '3 - Generic-legacy', @@ -266,6 +270,8 @@ class HP3PARCommon(object): raise exception.VolumeBackendAPIException(data=msg) try: self.client = self._create_client() + wsapi_version = self.client.getWsApiVersion() + self.API_VERSION = wsapi_version['build'] except hpexceptions.UnsupportedVersion as ex: raise exception.InvalidInput(ex) LOG.info(_LI("HP3PARCommon %(common_ver)s, hp3parclient %(rest_ver)s"), @@ -933,8 +939,8 @@ class HP3PARCommon(object): if persona_value not in self.valid_persona_values: err = (_("Must specify a valid persona %(valid)s," "value '%(persona)s' is invalid.") % - ({'valid': self.valid_persona_values, - 'persona': persona_value})) + {'valid': self.valid_persona_values, + 'persona': persona_value}) LOG.error(err) raise exception.InvalidInput(reason=err) # persona is set by the id so remove the text and return the id @@ -1016,21 +1022,34 @@ class HP3PARCommon(object): default_prov) # check for valid provisioning type if prov_value not in self.valid_prov_values: - err = _("Must specify a valid provisioning type %(valid)s, " - "value '%(prov)s' is invalid.") % \ - ({'valid': self.valid_prov_values, - 'prov': prov_value}) + err = (_("Must specify a valid provisioning type %(valid)s, " + "value '%(prov)s' is invalid.") % + {'valid': self.valid_prov_values, + 'prov': prov_value}) LOG.error(err) raise exception.InvalidInput(reason=err) tpvv = True + tdvv = False if prov_value == "full": tpvv = False + elif prov_value == "dedup": + tpvv = False + tdvv = True + + if tdvv and (self.API_VERSION < DEDUP_API_VERSION): + err = (_("Dedup is a valid provisioning type, " + "but requires WSAPI version '%(dedup_version)s' " + "version '%(version)s' is installed.") % + {'dedup_version': DEDUP_API_VERSION, + 'version': self.API_VERSION}) + LOG.error(err) + raise exception.InvalidInput(reason=err) return {'hp3par_keys': hp3par_keys, 'cpg': cpg, 'snap_cpg': snap_cpg, 'vvs_name': vvs_name, 'qos': qos, - 'tpvv': tpvv, 'volume_type': volume_type} + 'tpvv': tpvv, 'tdvv': tdvv, 'volume_type': volume_type} def get_volume_settings_from_type(self, volume, host=None): """Get 3PAR volume settings given a volume. @@ -1083,6 +1102,7 @@ class HP3PARCommon(object): cpg = type_info['cpg'] snap_cpg = type_info['snap_cpg'] tpvv = type_info['tpvv'] + tdvv = type_info['tdvv'] type_id = volume.get('volume_type_id', None) if type_id is not None: @@ -1097,6 +1117,10 @@ class HP3PARCommon(object): 'snapCPG': snap_cpg, 'tpvv': tpvv} + # Only set the dedup option if the backend supports it. + if self.API_VERSION >= DEDUP_API_VERSION: + extras['tdvv'] = tdvv + capacity = self._capacity_from_size(volume['size']) volume_name = self._get_3par_vol_name(volume['id']) self.client.createVolume(volume_name, cpg, capacity, extras) @@ -1129,7 +1153,7 @@ class HP3PARCommon(object): return self._get_model_update(volume['host'], cpg) def _copy_volume(self, src_name, dest_name, cpg, snap_cpg=None, - tpvv=True): + tpvv=True, tdvv=False): # Virtual volume sets are not supported with the -online option LOG.debug('Creating clone of a volume %(src)s to %(dest)s.', {'src': src_name, 'dest': dest_name}) @@ -1138,6 +1162,9 @@ class HP3PARCommon(object): if snap_cpg is not None: optional['snapCPG'] = snap_cpg + if self.API_VERSION >= DEDUP_API_VERSION: + optional['tdvv'] = tdvv + body = self.client.copyVolume(src_name, dest_name, cpg, optional) return body['taskid'] @@ -1194,7 +1221,8 @@ class HP3PARCommon(object): cpg = type_info['cpg'] self._copy_volume(orig_name, vol_name, cpg=cpg, snap_cpg=type_info['snap_cpg'], - tpvv=type_info['tpvv']) + tpvv=type_info['tpvv'], + tdvv=type_info['tdvv']) return self._get_model_update(volume['host'], cpg) @@ -1508,7 +1536,8 @@ class HP3PARCommon(object): # Create a physical copy of the volume task_id = self._copy_volume(volume_name, temp_vol_name, - cpg, cpg, type_info['tpvv']) + cpg, cpg, type_info['tpvv'], + type_info['tdvv']) LOG.debug('Copy volume scheduled: convert_to_base_volume: ' 'id=%s.', volume['id']) @@ -1659,7 +1688,8 @@ class HP3PARCommon(object): portPos['cardPort'] = int(split[2]) return portPos - def tune_vv(self, old_tpvv, new_tpvv, old_cpg, new_cpg, volume_name): + def tune_vv(self, old_tpvv, new_tpvv, old_tdvv, new_tdvv, + old_cpg, new_cpg, volume_name): """Tune the volume to change the userCPG and/or provisioningType. The volume will be modified/tuned/converted to the new userCPG and @@ -1670,7 +1700,7 @@ class HP3PARCommon(object): either be done or it is in a state that we need to treat as an error. """ - if old_tpvv == new_tpvv: + if old_tpvv == new_tpvv and old_tdvv == new_tdvv: if new_cpg != old_cpg: LOG.info(_LI("Modifying %(volume_name)s userCPG " "from %(old_cpg)s" @@ -1691,15 +1721,20 @@ class HP3PARCommon(object): {'status': status, 'volume_name': volume_name}) raise exception.VolumeBackendAPIException(msg) else: - if old_tpvv: - cop = self.CONVERT_TO_FULL - LOG.info(_LI("Converting %(volume_name)s to full provisioning " - "with userCPG=%(new_cpg)s"), - {'volume_name': volume_name, 'new_cpg': new_cpg}) - else: + if new_tpvv: cop = self.CONVERT_TO_THIN LOG.info(_LI("Converting %(volume_name)s to thin provisioning " - "with userCPG=%(new_cpg)s"), + "with userCPG=%(new_cpg)s") % + {'volume_name': volume_name, 'new_cpg': new_cpg}) + elif new_tdvv: + cop = self.CONVERT_TO_DEDUP + LOG.info(_LI("Converting %(volume_name)s to thin dedup " + "provisioning with userCPG=%(new_cpg)s") % + {'volume_name': volume_name, 'new_cpg': new_cpg}) + else: + cop = self.CONVERT_TO_FULL + LOG.info(_LI("Converting %(volume_name)s to full provisioning " + "with userCPG=%(new_cpg)s") % {'volume_name': volume_name, 'new_cpg': new_cpg}) try: @@ -1772,8 +1807,8 @@ class HP3PARCommon(object): def _retype(self, volume, volume_name, new_type_name, new_type_id, host, new_persona, old_cpg, new_cpg, old_snap_cpg, new_snap_cpg, - old_tpvv, new_tpvv, old_vvs, new_vvs, old_qos, new_qos, - old_comment): + old_tpvv, new_tpvv, old_tdvv, new_tdvv, old_vvs, new_vvs, + old_qos, new_qos, old_comment): action = "volume:retype" @@ -1796,6 +1831,7 @@ class HP3PARCommon(object): store={'common': self, 'volume_name': volume_name, 'volume': volume, 'old_tpvv': old_tpvv, 'new_tpvv': new_tpvv, + 'old_tdvv': old_tdvv, 'new_tdvv': new_tdvv, 'old_cpg': old_cpg, 'new_cpg': new_cpg, 'old_snap_cpg': old_snap_cpg, 'new_snap_cpg': new_snap_cpg, 'old_vvs': old_vvs, 'new_vvs': new_vvs, @@ -1836,6 +1872,7 @@ class HP3PARCommon(object): new_cpg = new_volume_settings['cpg'] new_snap_cpg = new_volume_settings['snap_cpg'] new_tpvv = new_volume_settings['tpvv'] + new_tdvv = new_volume_settings['tdvv'] new_qos = new_volume_settings['qos'] new_vvs = new_volume_settings['vvs_name'] new_persona = None @@ -1850,6 +1887,7 @@ class HP3PARCommon(object): # same settings that were used with this volume. old_volume_info = self.client.getVolume(volume_name) old_tpvv = old_volume_info['provisioningType'] == self.THIN + old_tdvv = old_volume_info['provisioningType'] == self.DEDUP old_cpg = old_volume_info['userCPG'] old_comment = old_volume_info['comment'] old_snap_cpg = None @@ -1863,7 +1901,8 @@ class HP3PARCommon(object): self._retype(volume, volume_name, new_type_name, new_type_id, host, new_persona, old_cpg, new_cpg, old_snap_cpg, new_snap_cpg, old_tpvv, new_tpvv, - old_vvs, new_vvs, old_qos, new_qos, old_comment) + old_tdvv, new_tdvv, old_vvs, new_vvs, old_qos, + new_qos, old_comment) if host: return True, self._get_model_update(host['host'], new_cpg) @@ -2037,9 +2076,10 @@ class TuneVolumeTask(flow_utils.CinderTask): def __init__(self, action, **kwargs): super(TuneVolumeTask, self).__init__(addons=[action]) - def execute(self, common, old_tpvv, new_tpvv, old_cpg, new_cpg, - volume_name): - common.tune_vv(old_tpvv, new_tpvv, old_cpg, new_cpg, volume_name) + def execute(self, common, old_tpvv, new_tpvv, old_tdvv, new_tdvv, + old_cpg, new_cpg, volume_name): + common.tune_vv(old_tpvv, new_tpvv, old_tdvv, new_tdvv, + old_cpg, new_cpg, volume_name) class ModifySpecsTask(flow_utils.CinderTask): -- 2.45.2