[Unity] Support create volume with tiering policy.
four supported values: - ``StartHighThenAuto``(default) - ``Auto`` - ``HighestAvailable`` - ``LowestAvailable`` Change-Id: I571cec8139b645f0899428ccd4479a2e11bb92d6
This commit is contained in:
parent
33b32d9820
commit
fb114ed943
24
cinder/tests/unit/volume/drivers/dell_emc/unity/fake_enum.py
Normal file
24
cinder/tests/unit/volume/drivers/dell_emc/unity/fake_enum.py
Normal file
@ -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')
|
@ -22,6 +22,8 @@ from oslo_utils import units
|
|||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder import test
|
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 \
|
from cinder.tests.unit.volume.drivers.dell_emc.unity \
|
||||||
import fake_exception as ex
|
import fake_exception as ex
|
||||||
from cinder.tests.unit.volume.drivers.dell_emc.unity import test_client
|
from cinder.tests.unit.volume.drivers.dell_emc.unity import test_client
|
||||||
@ -105,11 +107,15 @@ class MockClient(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_lun(name, size, pool, description=None, io_limit_policy=None,
|
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
|
lun_id = name
|
||||||
if is_thin is not None and not is_thin:
|
if is_thin is not None and not is_thin:
|
||||||
lun_id += '_thick'
|
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)
|
return test_client.MockResource(_id=lun_id, name=name)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -310,6 +316,10 @@ class MockOSResource(mock.Mock):
|
|||||||
super(MockOSResource, self).__init__(*args, **kwargs)
|
super(MockOSResource, self).__init__(*args, **kwargs)
|
||||||
if 'name' in kwargs:
|
if 'name' in kwargs:
|
||||||
self.name = kwargs['name']
|
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,
|
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':
|
if type_id == 'thick':
|
||||||
return {'provisioning:type': 'thick',
|
return {'provisioning:type': 'thick',
|
||||||
'thick_provisioning_support': '<is> True'}
|
'thick_provisioning_support': '<is> True'}
|
||||||
|
if type_id == 'tier_auto':
|
||||||
|
return {'storagetype:tiering': 'Auto',
|
||||||
|
'fast_support': '<is> True'}
|
||||||
|
if type_id == 'tier_lowest':
|
||||||
|
return {'storagetype:tiering': 'LowestAvailable',
|
||||||
|
'fast_support': '<is> True'}
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
@ -463,6 +479,7 @@ class IdMatcher(object):
|
|||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
@mock.patch.object(adapter, 'storops_ex', new=ex)
|
@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',
|
@mock.patch.object(adapter.volume_utils, 'is_group_a_cg_snapshot_type',
|
||||||
new=lambda x: True)
|
new=lambda x: True)
|
||||||
class CommonAdapterTest(test.TestCase):
|
class CommonAdapterTest(test.TestCase):
|
||||||
@ -503,6 +520,22 @@ class CommonAdapterTest(test.TestCase):
|
|||||||
expected = get_lun_pl('lun_3')
|
expected = get_lun_pl('lun_3')
|
||||||
self.assertEqual(expected, ret['provider_location'])
|
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):
|
def test_create_snapshot(self):
|
||||||
volume = MockOSResource(provider_location='id^lun_43')
|
volume = MockOSResource(provider_location='id^lun_43')
|
||||||
snap = MockOSResource(volume=volume, name='abc-def_snap')
|
snap = MockOSResource(volume=volume, name='abc-def_snap')
|
||||||
@ -547,6 +580,7 @@ class CommonAdapterTest(test.TestCase):
|
|||||||
self.assertTrue(stats['consistent_group_snapshot_enabled'])
|
self.assertTrue(stats['consistent_group_snapshot_enabled'])
|
||||||
self.assertFalse(stats['replication_enabled'])
|
self.assertFalse(stats['replication_enabled'])
|
||||||
self.assertEqual(0, len(stats['replication_targets']))
|
self.assertEqual(0, len(stats['replication_targets']))
|
||||||
|
self.assertTrue(stats['fast_support'])
|
||||||
|
|
||||||
def test_update_volume_stats(self):
|
def test_update_volume_stats(self):
|
||||||
stats = self.adapter.update_volume_stats()
|
stats = self.adapter.update_volume_stats()
|
||||||
@ -557,6 +591,7 @@ class CommonAdapterTest(test.TestCase):
|
|||||||
self.assertTrue(stats['consistent_group_snapshot_enabled'])
|
self.assertTrue(stats['consistent_group_snapshot_enabled'])
|
||||||
self.assertFalse(stats['replication_enabled'])
|
self.assertFalse(stats['replication_enabled'])
|
||||||
self.assertEqual(0, len(stats['replication_targets']))
|
self.assertEqual(0, len(stats['replication_targets']))
|
||||||
|
self.assertTrue(stats['fast_support'])
|
||||||
self.assertEqual(1, len(stats['pools']))
|
self.assertEqual(1, len(stats['pools']))
|
||||||
|
|
||||||
def test_get_replication_stats(self):
|
def test_get_replication_stats(self):
|
||||||
|
@ -19,6 +19,8 @@ from mock import mock
|
|||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
|
||||||
from cinder import coordination
|
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 \
|
from cinder.tests.unit.volume.drivers.dell_emc.unity \
|
||||||
import fake_exception as ex
|
import fake_exception as ex
|
||||||
from cinder.volume.drivers.dell_emc.unity import client
|
from cinder.volume.drivers.dell_emc.unity import client
|
||||||
@ -55,6 +57,8 @@ class MockResource(object):
|
|||||||
self.description = None
|
self.description = None
|
||||||
self.luns = None
|
self.luns = None
|
||||||
self.lun = None
|
self.lun = None
|
||||||
|
self.tiering_policy = None
|
||||||
|
self.pool_fast_vp = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
@ -124,7 +128,7 @@ class MockResource(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_lun(lun_name, size_gb, description=None, io_limit_policy=None,
|
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':
|
if lun_name == 'in_use':
|
||||||
raise ex.UnityLunNameInUseError()
|
raise ex.UnityLunNameInUseError()
|
||||||
ret = MockResource(lun_name, 'lun_2')
|
ret = MockResource(lun_name, 'lun_2')
|
||||||
@ -133,6 +137,8 @@ class MockResource(object):
|
|||||||
ret.max_kbps = io_limit_policy.max_kbps
|
ret.max_kbps = io_limit_policy.max_kbps
|
||||||
if is_thin is not None:
|
if is_thin is not None:
|
||||||
ret.is_thin = is_thin
|
ret.is_thin = is_thin
|
||||||
|
if tiering_policy is not None:
|
||||||
|
ret.tiering_policy = tiering_policy
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -416,6 +422,25 @@ class ClientTest(unittest.TestCase):
|
|||||||
lun = self.client.create_lun(name, 6, pool, is_thin=False)
|
lun = self.client.create_lun(name, 6, pool, is_thin=False)
|
||||||
self.assertIsNotNone(lun.is_thin)
|
self.assertIsNotNone(lun.is_thin)
|
||||||
self.assertFalse(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):
|
def test_thin_clone_success(self):
|
||||||
name = 'tc_77'
|
name = 'tc_77'
|
||||||
|
@ -35,9 +35,11 @@ from cinder.volume import volume_utils
|
|||||||
storops = importutils.try_import('storops')
|
storops = importutils.try_import('storops')
|
||||||
if storops:
|
if storops:
|
||||||
from storops import exception as storops_ex
|
from storops import exception as storops_ex
|
||||||
|
from storops.unity import enums
|
||||||
else:
|
else:
|
||||||
# Set storops_ex to be None for unit test
|
# Set storops_ex to be None for unit test
|
||||||
storops_ex = None
|
storops_ex = None
|
||||||
|
enums = None
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -62,6 +64,7 @@ class VolumeParams(object):
|
|||||||
self._is_compressed = None
|
self._is_compressed = None
|
||||||
self._is_in_cg = None
|
self._is_in_cg = None
|
||||||
self._is_replication_enabled = None
|
self._is_replication_enabled = None
|
||||||
|
self._tiering_policy = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume_id(self):
|
def volume_id(self):
|
||||||
@ -144,6 +147,27 @@ class VolumeParams(object):
|
|||||||
self._volume.group))
|
self._volume.group))
|
||||||
return self._is_in_cg
|
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') == '<is> 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
|
@property
|
||||||
def cg_id(self):
|
def cg_id(self):
|
||||||
if self.is_in_cg:
|
if self.is_in_cg:
|
||||||
@ -166,6 +190,7 @@ class VolumeParams(object):
|
|||||||
self.is_compressed == other.is_compressed and
|
self.is_compressed == other.is_compressed and
|
||||||
self.is_in_cg == other.is_in_cg and
|
self.is_in_cg == other.is_in_cg and
|
||||||
self.cg_id == other.cg_id and
|
self.cg_id == other.cg_id and
|
||||||
|
self.tiering_policy == other.tiering_policy and
|
||||||
self.is_replication_enabled == other.is_replication_enabled)
|
self.is_replication_enabled == other.is_replication_enabled)
|
||||||
|
|
||||||
|
|
||||||
@ -365,7 +390,8 @@ class CommonAdapter(object):
|
|||||||
'is_thick': params.is_thick,
|
'is_thick': params.is_thick,
|
||||||
'is_compressed': params.is_compressed,
|
'is_compressed': params.is_compressed,
|
||||||
'cg_id': params.cg_id,
|
'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: '
|
LOG.info('Create Volume: %(name)s, size: %(size)s, description: '
|
||||||
@ -382,8 +408,8 @@ class CommonAdapter(object):
|
|||||||
description=params.description,
|
description=params.description,
|
||||||
io_limit_policy=params.io_limit_policy,
|
io_limit_policy=params.io_limit_policy,
|
||||||
is_thin=False if params.is_thick else None,
|
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:
|
if params.cg_id:
|
||||||
LOG.debug('Adding lun %(lun)s to cg %(cg)s.',
|
LOG.debug('Adding lun %(lun)s to cg %(cg)s.',
|
||||||
{'lun': lun.get_id(), 'cg': params.cg_id})
|
{'lun': lun.get_id(), 'cg': params.cg_id})
|
||||||
|
@ -58,7 +58,7 @@ class UnityClient(object):
|
|||||||
|
|
||||||
def create_lun(self, name, size, pool, description=None,
|
def create_lun(self, name, size, pool, description=None,
|
||||||
io_limit_policy=None, is_thin=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.
|
"""Creates LUN on the Unity system.
|
||||||
|
|
||||||
:param name: lun name
|
:param name: lun name
|
||||||
@ -68,6 +68,7 @@ class UnityClient(object):
|
|||||||
:param io_limit_policy: io limit on the LUN
|
:param io_limit_policy: io limit on the LUN
|
||||||
:param is_thin: if False, a thick LUN will be created
|
:param is_thin: if False, a thick LUN will be created
|
||||||
:param is_compressed: is compressed LUN enabled
|
: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
|
:param cg_name: the name of cg to join if any
|
||||||
:return: UnityLun object
|
:return: UnityLun object
|
||||||
"""
|
"""
|
||||||
@ -76,7 +77,8 @@ class UnityClient(object):
|
|||||||
description=description,
|
description=description,
|
||||||
io_limit_policy=io_limit_policy,
|
io_limit_policy=io_limit_policy,
|
||||||
is_thin=is_thin,
|
is_thin=is_thin,
|
||||||
is_compression=is_compressed)
|
is_compression=is_compressed,
|
||||||
|
tiering_policy=tiering_policy)
|
||||||
except storops_ex.UnityLunNameInUseError:
|
except storops_ex.UnityLunNameInUseError:
|
||||||
LOG.debug("LUN %s already exists. Return the existing one.",
|
LOG.debug("LUN %s already exists. Return the existing one.",
|
||||||
name)
|
name)
|
||||||
|
@ -82,9 +82,10 @@ class UnityDriver(driver.ManageableVD,
|
|||||||
5.0.0 - Support storage assisted volume migration
|
5.0.0 - Support storage assisted volume migration
|
||||||
6.0.0 - Support generic group and consistent group
|
6.0.0 - Support generic group and consistent group
|
||||||
6.1.0 - Support volume replication
|
6.1.0 - Support volume replication
|
||||||
|
7.0.0 - Support tiering policy
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = '06.01.00'
|
VERSION = '07.00.00'
|
||||||
VENDOR = 'Dell EMC'
|
VENDOR = 'Dell EMC'
|
||||||
# ThirdPartySystems wiki page
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "EMC_UNITY_CI"
|
CI_WIKI_NAME = "EMC_UNITY_CI"
|
||||||
|
@ -325,7 +325,8 @@ def append_capabilities(func):
|
|||||||
capabilities = {
|
capabilities = {
|
||||||
'thin_provisioning_support': True,
|
'thin_provisioning_support': True,
|
||||||
'thick_provisioning_support': True,
|
'thick_provisioning_support': True,
|
||||||
'consistent_group_snapshot_enabled': True
|
'consistent_group_snapshot_enabled': True,
|
||||||
|
'fast_support': True
|
||||||
}
|
}
|
||||||
|
|
||||||
@six.wraps(func)
|
@six.wraps(func)
|
||||||
|
@ -35,6 +35,7 @@ Supported operations
|
|||||||
- Efficient non-disruptive volume backup.
|
- Efficient non-disruptive volume backup.
|
||||||
- Revert a volume to a snapshot.
|
- Revert a volume to a snapshot.
|
||||||
- Create thick volumes.
|
- Create thick volumes.
|
||||||
|
- Create volume with tiering policy.
|
||||||
- Create and delete consistent groups.
|
- Create and delete consistent groups.
|
||||||
- Add/remove volumes to/from a consistent group.
|
- Add/remove volumes to/from a consistent group.
|
||||||
- Create and delete consistent group snapshots.
|
- Create and delete consistent group snapshots.
|
||||||
@ -301,6 +302,35 @@ consumer type. ``maxBWS`` represents the ``Maximum IO/S`` absolute limit,
|
|||||||
Unity respectively.
|
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='<is> 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='<is> True' VolumeOnAutoTier
|
||||||
|
|
||||||
|
|
||||||
Auto-zoning support
|
Auto-zoning support
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Dell EMC Unity driver: Add tiering policy configuration support for volume.
|
Loading…
x
Reference in New Issue
Block a user