[Unity] Compressed volume support
Support operations are: Create/delete/clone/extend/attach/detach compressed volumes Change-Id: I43d840875ebb99744d23d87482603e34551c3882 Implements: blueprint unity-compressed-volume-support
This commit is contained in:
parent
688ff8157d
commit
2da949da1f
@ -79,7 +79,7 @@ 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_thin=None, is_compressed=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'
|
||||||
@ -391,6 +391,16 @@ class CommonAdapterTest(test.TestCase):
|
|||||||
expected = get_lun_pl('lun_3_thick')
|
expected = get_lun_pl('lun_3_thick')
|
||||||
self.assertEqual(expected, ret['provider_location'])
|
self.assertEqual(expected, ret['provider_location'])
|
||||||
|
|
||||||
|
@patch_for_unity_adapter
|
||||||
|
def test_create_compressed_volume(self):
|
||||||
|
volume_type = MockOSResource(
|
||||||
|
extra_specs={'compression_support': '<is> True'})
|
||||||
|
volume = MockOSResource(name='lun_3', size=5, host='unity#pool1',
|
||||||
|
volume_type=volume_type)
|
||||||
|
ret = self.adapter.create_volume(volume)
|
||||||
|
expected = get_lun_pl('lun_3')
|
||||||
|
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')
|
||||||
@ -431,6 +441,7 @@ class CommonAdapterTest(test.TestCase):
|
|||||||
self.assertEqual(5, stats['reserved_percentage'])
|
self.assertEqual(5, stats['reserved_percentage'])
|
||||||
self.assertTrue(stats['thick_provisioning_support'])
|
self.assertTrue(stats['thick_provisioning_support'])
|
||||||
self.assertTrue(stats['thin_provisioning_support'])
|
self.assertTrue(stats['thin_provisioning_support'])
|
||||||
|
self.assertTrue(stats['compression_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()
|
||||||
|
@ -49,6 +49,7 @@ class MockResource(object):
|
|||||||
self._storage_resource = None
|
self._storage_resource = None
|
||||||
self.host_cache = []
|
self.host_cache = []
|
||||||
self.is_thin = None
|
self.is_thin = None
|
||||||
|
self.is_all_flash = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
@ -113,7 +114,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_thin=None, is_compression=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')
|
||||||
|
@ -58,6 +58,7 @@ class VolumeParams(object):
|
|||||||
self._pool = None
|
self._pool = None
|
||||||
self._io_limit_policy = None
|
self._io_limit_policy = None
|
||||||
self._is_thick = None
|
self._is_thick = None
|
||||||
|
self._is_compressed = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume_id(self):
|
def volume_id(self):
|
||||||
@ -118,12 +119,27 @@ class VolumeParams(object):
|
|||||||
self._is_thick = (provision == 'thick' and support == '<is> True')
|
self._is_thick = (provision == 'thick' and support == '<is> True')
|
||||||
return self._is_thick
|
return self._is_thick
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_compressed(self):
|
||||||
|
if self._is_compressed is None:
|
||||||
|
provision = utils.get_extra_spec(self._volume, 'provisioning:type')
|
||||||
|
compression = utils.get_extra_spec(self._volume,
|
||||||
|
'compression_support')
|
||||||
|
if provision == 'compressed' and compression == '<is> True':
|
||||||
|
self._is_compressed = True
|
||||||
|
return self._is_compressed
|
||||||
|
|
||||||
|
@is_compressed.setter
|
||||||
|
def is_compressed(self, value):
|
||||||
|
self._is_compressed = value
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return (self.volume_id == other.volume_id and
|
return (self.volume_id == other.volume_id and
|
||||||
self.name == other.name and
|
self.name == other.name and
|
||||||
self.size == other.size and
|
self.size == other.size and
|
||||||
self.io_limit_policy == other.io_limit_policy and
|
self.io_limit_policy == other.io_limit_policy and
|
||||||
self.is_thick == other.is_thick)
|
self.is_thick == other.is_thick and
|
||||||
|
self.is_compressed == other.is_compressed)
|
||||||
|
|
||||||
|
|
||||||
class CommonAdapter(object):
|
class CommonAdapter(object):
|
||||||
@ -285,12 +301,14 @@ class CommonAdapter(object):
|
|||||||
'description': params.description,
|
'description': params.description,
|
||||||
'pool': params.pool,
|
'pool': params.pool,
|
||||||
'io_limit_policy': params.io_limit_policy,
|
'io_limit_policy': params.io_limit_policy,
|
||||||
'is_thick': params.is_thick
|
'is_thick': params.is_thick,
|
||||||
|
'is_compressed': params.is_compressed
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.info('Create Volume: %(name)s, size: %(size)s, description: '
|
LOG.info('Create Volume: %(name)s, size: %(size)s, description: '
|
||||||
'%(description)s, pool: %(pool)s, io limit policy: '
|
'%(description)s, pool: %(pool)s, io limit policy: '
|
||||||
'%(io_limit_policy)s, thick: %(is_thick)s.', log_params)
|
'%(io_limit_policy)s, thick: %(is_thick)s, '
|
||||||
|
'%(is_compressed)s.', log_params)
|
||||||
|
|
||||||
return self.makeup_model(
|
return self.makeup_model(
|
||||||
self.client.create_lun(name=params.name,
|
self.client.create_lun(name=params.name,
|
||||||
@ -298,7 +316,8 @@ class CommonAdapter(object):
|
|||||||
pool=params.pool,
|
pool=params.pool,
|
||||||
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))
|
||||||
|
|
||||||
def delete_volume(self, volume):
|
def delete_volume(self, volume):
|
||||||
lun_id = self.get_lun_id(volume)
|
lun_id = self.get_lun_id(volume)
|
||||||
@ -442,6 +461,7 @@ class CommonAdapter(object):
|
|||||||
'array_serial': self.serial_number}),
|
'array_serial': self.serial_number}),
|
||||||
'thin_provisioning_support': True,
|
'thin_provisioning_support': True,
|
||||||
'thick_provisioning_support': True,
|
'thick_provisioning_support': True,
|
||||||
|
'compression_support': pool.is_all_flash,
|
||||||
'max_over_subscription_ratio': (
|
'max_over_subscription_ratio': (
|
||||||
self.max_over_subscription_ratio)}
|
self.max_over_subscription_ratio)}
|
||||||
|
|
||||||
@ -597,7 +617,8 @@ class CommonAdapter(object):
|
|||||||
name=vol_params.name, size=vol_params.size, pool=vol_params.pool,
|
name=vol_params.name, size=vol_params.size, pool=vol_params.pool,
|
||||||
description=vol_params.description,
|
description=vol_params.description,
|
||||||
io_limit_policy=vol_params.io_limit_policy,
|
io_limit_policy=vol_params.io_limit_policy,
|
||||||
is_thin=False if vol_params.is_thick else None)
|
is_thin=False if vol_params.is_thick else None,
|
||||||
|
is_compressed=vol_params.is_compressed)
|
||||||
src_id = src_snap.get_id()
|
src_id = src_snap.get_id()
|
||||||
try:
|
try:
|
||||||
conn_props = cinder_utils.brick_get_connector_properties()
|
conn_props = cinder_utils.brick_get_connector_properties()
|
||||||
|
@ -57,7 +57,8 @@ class UnityClient(object):
|
|||||||
return self.system.serial_number
|
return self.system.serial_number
|
||||||
|
|
||||||
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):
|
||||||
"""Creates LUN on the Unity system.
|
"""Creates LUN on the Unity system.
|
||||||
|
|
||||||
:param name: lun name
|
:param name: lun name
|
||||||
@ -66,13 +67,15 @@ class UnityClient(object):
|
|||||||
:param description: lun description
|
:param description: lun description
|
||||||
: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
|
||||||
:return: UnityLun object
|
:return: UnityLun object
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
lun = pool.create_lun(lun_name=name, size_gb=size,
|
lun = pool.create_lun(lun_name=name, size_gb=size,
|
||||||
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)
|
||||||
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)
|
||||||
|
@ -58,9 +58,10 @@ class UnityDriver(driver.ManageableVD,
|
|||||||
3.0.0 - Add IPv6 support
|
3.0.0 - Add IPv6 support
|
||||||
3.1.0 - Support revert to snapshot API
|
3.1.0 - Support revert to snapshot API
|
||||||
4.0.0 - Support remove empty host
|
4.0.0 - Support remove empty host
|
||||||
|
4.2.0 - Support compressed volume
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = '04.00.00'
|
VERSION = '04.02.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"
|
||||||
|
@ -23,6 +23,7 @@ Supported operations
|
|||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
- Create, delete, attach, and detach volumes.
|
- Create, delete, attach, and detach volumes.
|
||||||
|
- Create, delete, attach, and detach compressed volumes.
|
||||||
- Create, list, and delete volume snapshots.
|
- Create, list, and delete volume snapshots.
|
||||||
- Create a volume from a snapshot.
|
- Create a volume from a snapshot.
|
||||||
- Copy an image to a volume.
|
- Copy an image to a volume.
|
||||||
@ -248,6 +249,21 @@ following commands to create a thick volume.
|
|||||||
# openstack volume create --type thick_volume_type thick_volume
|
# openstack volume create --type thick_volume_type thick_volume
|
||||||
|
|
||||||
|
|
||||||
|
Compressed volume support
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Unity driver supports ``compressed volume`` creation, modification and
|
||||||
|
deletion. In order to create a compressed volume, a volume type which
|
||||||
|
enables compression support needs to be created first:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ openstack volume type create CompressedVolumeType
|
||||||
|
$ openstack volume type set --property provisioning:type=compressed --property compression_support='<is> True' CompressedVolumeType
|
||||||
|
|
||||||
|
Then create volume and specify the new created volume type.
|
||||||
|
|
||||||
|
|
||||||
QoS support
|
QoS support
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Dell EMC Unity driver: Add compressed volume support.
|
Loading…
x
Reference in New Issue
Block a user