diff --git a/cinder/tests/unit/volume/drivers/dell_emc/unity/fake_enum.py b/cinder/tests/unit/volume/drivers/dell_emc/unity/fake_enum.py new file mode 100644 index 00000000000..fd8a5612a53 --- /dev/null +++ b/cinder/tests/unit/volume/drivers/dell_emc/unity/fake_enum.py @@ -0,0 +1,24 @@ +# Copyright (c) 2017-2019 Dell Inc. or its subsidiaries. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +import enum + + +class TieringPolicyEnum(enum.Enum): + AUTOTIER_HIGH = (0, 'Start Highest and Auto-tier') + AUTOTIER = (1, 'Auto-tier') + HIGHEST = (2, 'Highest') + LOWEST = (3, 'Lowest') + NO_DATA_MOVEMENT = (4, 'No Data Movement') + MIXED = (0xffff, 'Different Tier Policies') diff --git a/cinder/tests/unit/volume/drivers/dell_emc/unity/test_adapter.py b/cinder/tests/unit/volume/drivers/dell_emc/unity/test_adapter.py index 6696f59b6cb..af92dd3351e 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/unity/test_adapter.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/unity/test_adapter.py @@ -22,6 +22,8 @@ from oslo_utils import units from cinder import exception from cinder import test +from cinder.tests.unit.volume.drivers.dell_emc.unity \ + import fake_enum as enums from cinder.tests.unit.volume.drivers.dell_emc.unity \ import fake_exception as ex from cinder.tests.unit.volume.drivers.dell_emc.unity import test_client @@ -105,11 +107,15 @@ class MockClient(object): @staticmethod def create_lun(name, size, pool, description=None, io_limit_policy=None, - is_thin=None, is_compressed=None): + is_thin=None, is_compressed=None, tiering_policy=None): lun_id = name if is_thin is not None and not is_thin: lun_id += '_thick' - + if tiering_policy: + if tiering_policy is enums.TieringPolicyEnum.AUTOTIER: + lun_id += '_auto' + elif tiering_policy is enums.TieringPolicyEnum.LOWEST: + lun_id += '_low' return test_client.MockResource(_id=lun_id, name=name) @staticmethod @@ -310,6 +316,10 @@ class MockOSResource(mock.Mock): super(MockOSResource, self).__init__(*args, **kwargs) if 'name' in kwargs: self.name = kwargs['name'] + self.kwargs = kwargs + + def __getitem__(self, key): + return self.kwargs[key] def mock_replication_device(device_conf=None, serial_number=None, @@ -380,6 +390,12 @@ def get_volume_type_extra_specs(type_id): if type_id == 'thick': return {'provisioning:type': 'thick', 'thick_provisioning_support': ' True'} + if type_id == 'tier_auto': + return {'storagetype:tiering': 'Auto', + 'fast_support': ' True'} + if type_id == 'tier_lowest': + return {'storagetype:tiering': 'LowestAvailable', + 'fast_support': ' True'} return {} @@ -463,6 +479,7 @@ class IdMatcher(object): @ddt.ddt @mock.patch.object(adapter, 'storops_ex', new=ex) +@mock.patch.object(adapter, 'enums', new=enums) @mock.patch.object(adapter.volume_utils, 'is_group_a_cg_snapshot_type', new=lambda x: True) class CommonAdapterTest(test.TestCase): @@ -503,6 +520,22 @@ class CommonAdapterTest(test.TestCase): expected = get_lun_pl('lun_3') self.assertEqual(expected, ret['provider_location']) + @patch_for_unity_adapter + def test_create_auto_tiering_volume(self): + volume = MockOSResource(name='lun_3', size=5, host='unity#pool1', + group=None, volume_type_id='tier_auto') + ret = self.adapter.create_volume(volume) + expected = get_lun_pl('lun_3_auto') + self.assertEqual(expected, ret['provider_location']) + + @patch_for_unity_adapter + def test_create_lowest_tiering_volume(self): + volume = MockOSResource(name='lun_3', size=5, host='unity#pool1', + group=None, volume_type_id='tier_lowest') + ret = self.adapter.create_volume(volume) + expected = get_lun_pl('lun_3_low') + self.assertEqual(expected, ret['provider_location']) + def test_create_snapshot(self): volume = MockOSResource(provider_location='id^lun_43') snap = MockOSResource(volume=volume, name='abc-def_snap') @@ -547,6 +580,7 @@ class CommonAdapterTest(test.TestCase): self.assertTrue(stats['consistent_group_snapshot_enabled']) self.assertFalse(stats['replication_enabled']) self.assertEqual(0, len(stats['replication_targets'])) + self.assertTrue(stats['fast_support']) def test_update_volume_stats(self): stats = self.adapter.update_volume_stats() @@ -557,6 +591,7 @@ class CommonAdapterTest(test.TestCase): self.assertTrue(stats['consistent_group_snapshot_enabled']) self.assertFalse(stats['replication_enabled']) self.assertEqual(0, len(stats['replication_targets'])) + self.assertTrue(stats['fast_support']) self.assertEqual(1, len(stats['pools'])) def test_get_replication_stats(self): diff --git a/cinder/tests/unit/volume/drivers/dell_emc/unity/test_client.py b/cinder/tests/unit/volume/drivers/dell_emc/unity/test_client.py index e2b05516482..9ad118b81a8 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/unity/test_client.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/unity/test_client.py @@ -19,6 +19,8 @@ import ddt from oslo_utils import units from cinder import coordination +from cinder.tests.unit.volume.drivers.dell_emc.unity \ + import fake_enum as enums from cinder.tests.unit.volume.drivers.dell_emc.unity \ import fake_exception as ex from cinder.volume.drivers.dell_emc.unity import client @@ -55,6 +57,8 @@ class MockResource(object): self.description = None self.luns = None self.lun = None + self.tiering_policy = None + self.pool_fast_vp = None @property def id(self): @@ -124,7 +128,7 @@ class MockResource(object): @staticmethod def create_lun(lun_name, size_gb, description=None, io_limit_policy=None, - is_thin=None, is_compression=None): + is_thin=None, is_compression=None, tiering_policy=None): if lun_name == 'in_use': raise ex.UnityLunNameInUseError() ret = MockResource(lun_name, 'lun_2') @@ -133,6 +137,8 @@ class MockResource(object): ret.max_kbps = io_limit_policy.max_kbps if is_thin is not None: ret.is_thin = is_thin + if tiering_policy is not None: + ret.tiering_policy = tiering_policy return ret @staticmethod @@ -416,6 +422,25 @@ class ClientTest(unittest.TestCase): lun = self.client.create_lun(name, 6, pool, is_thin=False) self.assertIsNotNone(lun.is_thin) self.assertFalse(lun.is_thin) + self.assertIsNone(lun.tiering_policy) + + def test_create_auto_tier_lun(self): + name = 'auto_tier_lun' + tiering_policy = enums.TieringPolicyEnum.AUTOTIER + pool = MockResource('Pool 0') + lun = self.client.create_lun(name, 6, pool, + tiering_policy=tiering_policy) + self.assertIsNotNone(lun.tiering_policy) + self.assertEqual(enums.TieringPolicyEnum.AUTOTIER, lun.tiering_policy) + + def test_create_high_tier_lun(self): + name = 'high_tier_lun' + tiering_policy = enums.TieringPolicyEnum.HIGHEST + pool = MockResource('Pool 0') + lun = self.client.create_lun(name, 6, pool, + tiering_policy=tiering_policy) + self.assertIsNotNone(lun.tiering_policy) + self.assertEqual(enums.TieringPolicyEnum.HIGHEST, lun.tiering_policy) def test_thin_clone_success(self): name = 'tc_77' diff --git a/cinder/volume/drivers/dell_emc/unity/adapter.py b/cinder/volume/drivers/dell_emc/unity/adapter.py index 969daf86f95..56746467d80 100644 --- a/cinder/volume/drivers/dell_emc/unity/adapter.py +++ b/cinder/volume/drivers/dell_emc/unity/adapter.py @@ -35,9 +35,11 @@ from cinder.volume import volume_utils storops = importutils.try_import('storops') if storops: from storops import exception as storops_ex + from storops.unity import enums else: # Set storops_ex to be None for unit test storops_ex = None + enums = None LOG = logging.getLogger(__name__) @@ -62,6 +64,7 @@ class VolumeParams(object): self._is_compressed = None self._is_in_cg = None self._is_replication_enabled = None + self._tiering_policy = None @property def volume_id(self): @@ -144,6 +147,27 @@ class VolumeParams(object): self._volume.group)) return self._is_in_cg + @property + def tiering_policy(self): + tiering_policy_map = {'StartHighThenAuto': + enums.TieringPolicyEnum.AUTOTIER_HIGH, + 'Auto': + enums.TieringPolicyEnum.AUTOTIER, + 'HighestAvailable': + enums.TieringPolicyEnum.HIGHEST, + 'LowestAvailable': + enums.TieringPolicyEnum.LOWEST} + if not self._tiering_policy: + tiering_value = utils.get_extra_spec(self._volume, + 'storagetype:tiering') + support = utils.get_extra_spec(self._volume, + 'fast_support') == ' True' + + if tiering_value and support: + self._tiering_policy = tiering_policy_map.get(tiering_value) + # if no value, unity sets StartHighThenAuto as default + return self._tiering_policy + @property def cg_id(self): if self.is_in_cg: @@ -166,6 +190,7 @@ class VolumeParams(object): self.is_compressed == other.is_compressed and self.is_in_cg == other.is_in_cg and self.cg_id == other.cg_id and + self.tiering_policy == other.tiering_policy and self.is_replication_enabled == other.is_replication_enabled) @@ -365,7 +390,8 @@ class CommonAdapter(object): 'is_thick': params.is_thick, 'is_compressed': params.is_compressed, 'cg_id': params.cg_id, - 'is_replication_enabled': params.is_replication_enabled + 'is_replication_enabled': params.is_replication_enabled, + 'tiering_policy': params.tiering_policy } LOG.info('Create Volume: %(name)s, size: %(size)s, description: ' @@ -382,8 +408,8 @@ class CommonAdapter(object): description=params.description, io_limit_policy=params.io_limit_policy, is_thin=False if params.is_thick else None, - is_compressed=params.is_compressed) - + is_compressed=params.is_compressed, + tiering_policy=params.tiering_policy) if params.cg_id: LOG.debug('Adding lun %(lun)s to cg %(cg)s.', {'lun': lun.get_id(), 'cg': params.cg_id}) diff --git a/cinder/volume/drivers/dell_emc/unity/client.py b/cinder/volume/drivers/dell_emc/unity/client.py index f054c4ac286..fb7b27d6364 100644 --- a/cinder/volume/drivers/dell_emc/unity/client.py +++ b/cinder/volume/drivers/dell_emc/unity/client.py @@ -58,7 +58,7 @@ class UnityClient(object): def create_lun(self, name, size, pool, description=None, io_limit_policy=None, is_thin=None, - is_compressed=None, cg_name=None): + is_compressed=None, cg_name=None, tiering_policy=None): """Creates LUN on the Unity system. :param name: lun name @@ -68,6 +68,7 @@ class UnityClient(object): :param io_limit_policy: io limit on the LUN :param is_thin: if False, a thick LUN will be created :param is_compressed: is compressed LUN enabled + :param tiering_policy: tiering policy for the LUN :param cg_name: the name of cg to join if any :return: UnityLun object """ @@ -76,7 +77,8 @@ class UnityClient(object): description=description, io_limit_policy=io_limit_policy, is_thin=is_thin, - is_compression=is_compressed) + is_compression=is_compressed, + tiering_policy=tiering_policy) except storops_ex.UnityLunNameInUseError: LOG.debug("LUN %s already exists. Return the existing one.", name) diff --git a/cinder/volume/drivers/dell_emc/unity/driver.py b/cinder/volume/drivers/dell_emc/unity/driver.py index 38e2f98344f..b5b6bed710d 100644 --- a/cinder/volume/drivers/dell_emc/unity/driver.py +++ b/cinder/volume/drivers/dell_emc/unity/driver.py @@ -81,9 +81,10 @@ class UnityDriver(driver.ManageableVD, 5.0.0 - Support storage assisted volume migration 6.0.0 - Support generic group and consistent group 6.1.0 - Support volume replication + 7.0.0 - Support tiering policy """ - VERSION = '06.01.00' + VERSION = '07.00.00' VENDOR = 'Dell EMC' # ThirdPartySystems wiki page CI_WIKI_NAME = "EMC_UNITY_CI" diff --git a/cinder/volume/drivers/dell_emc/unity/utils.py b/cinder/volume/drivers/dell_emc/unity/utils.py index 70a5f86e532..185136f0e1a 100644 --- a/cinder/volume/drivers/dell_emc/unity/utils.py +++ b/cinder/volume/drivers/dell_emc/unity/utils.py @@ -325,7 +325,8 @@ def append_capabilities(func): capabilities = { 'thin_provisioning_support': True, 'thick_provisioning_support': True, - 'consistent_group_snapshot_enabled': True + 'consistent_group_snapshot_enabled': True, + 'fast_support': True } @six.wraps(func) diff --git a/doc/source/configuration/block-storage/drivers/dell-emc-unity-driver.rst b/doc/source/configuration/block-storage/drivers/dell-emc-unity-driver.rst index d6b7d6d7d78..299828ae6d1 100644 --- a/doc/source/configuration/block-storage/drivers/dell-emc-unity-driver.rst +++ b/doc/source/configuration/block-storage/drivers/dell-emc-unity-driver.rst @@ -35,6 +35,7 @@ Supported operations - Efficient non-disruptive volume backup. - Revert a volume to a snapshot. - Create thick volumes. +- Create volume with tiering policy. - Create and delete consistent groups. - Add/remove volumes to/from a consistent group. - Create and delete consistent group snapshots. @@ -303,6 +304,35 @@ consumer type. ``maxBWS`` represents the ``Maximum IO/S`` absolute limit, Unity respectively. +Storage tiering support +~~~~~~~~~~~~~~~~~~~~~~~ + +Unity supports fully automated storage tiering which requires the FAST VP +license activated on the Unity. The OpenStack administrator can use the extra +spec key ``storagetype:tiering`` to set the tiering policy of a volume and +use the key ``fast_support=' True'`` to let Block Storage scheduler find +a volume back end which manages a Unity with FAST VP license activated. There +are four supported values for the extra spec key ``storagetype:tiering`` +when creating volume. + +- Key: ``storagetype:tiering`` +- Possible values: + + - ``StartHighThenAuto`` + - ``Auto`` + - ``HighestAvailable`` + - ``LowestAvailable`` + +- Default: ``StartHighThenAuto`` + +Run the following commands to create a volume type with tiering policy: + +.. code-block:: console + + $ openstack volume type create VolumeOnAutoTier + $ openstack volume type set --property storagetype:tiering=Auto --property fast_support=' True' VolumeOnAutoTier + + Auto-zoning support ~~~~~~~~~~~~~~~~~~~ diff --git a/releasenotes/notes/unity-volume-tiering-policy-support-c6d0aaff4b141bd3.yaml b/releasenotes/notes/unity-volume-tiering-policy-support-c6d0aaff4b141bd3.yaml new file mode 100644 index 00000000000..72f063c7d83 --- /dev/null +++ b/releasenotes/notes/unity-volume-tiering-policy-support-c6d0aaff4b141bd3.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Dell EMC Unity driver: Add tiering policy configuration support for volume. \ No newline at end of file