Over subscription for Pure Storage iSCSI driver.
Add support for over subscription in Pure Storage iSCSI driver. Implements: blueprint pure-iscsi-over-subscription-thin-provisioning Change-Id: Ia9de828ad718c0790f4f04ee2a2f1eb4c3fe2788
This commit is contained in:
parent
8bda008dd0
commit
d469062417
|
@ -103,11 +103,16 @@ PORTS_WITHOUT = [NON_ISCSI_PORT]
|
||||||
VOLUME_CONNECTIONS = [{"host": "h1", "name": VOLUME["name"] + "-cinder"},
|
VOLUME_CONNECTIONS = [{"host": "h1", "name": VOLUME["name"] + "-cinder"},
|
||||||
{"host": "h2", "name": VOLUME["name"] + "-cinder"},
|
{"host": "h2", "name": VOLUME["name"] + "-cinder"},
|
||||||
]
|
]
|
||||||
TOTAL_SPACE = 50.0
|
TOTAL_CAPACITY = 50.0
|
||||||
FREE_SPACE = 32.1
|
USED_SPACE = 32.1
|
||||||
SPACE_INFO = {"capacity": TOTAL_SPACE * units.Gi,
|
PROVISIONED_CAPACITY = 70.0
|
||||||
"total": (TOTAL_SPACE - FREE_SPACE) * units.Gi,
|
DEFAULT_OVER_SUBSCRIPTION = 20
|
||||||
|
SPACE_INFO = {"capacity": TOTAL_CAPACITY * units.Gi,
|
||||||
|
"total": USED_SPACE * units.Gi
|
||||||
}
|
}
|
||||||
|
SPACE_INFO_EMPTY = {"capacity": TOTAL_CAPACITY * units.Gi,
|
||||||
|
"total": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class FakePureStorageHTTPError(Exception):
|
class FakePureStorageHTTPError(Exception):
|
||||||
|
@ -570,17 +575,65 @@ class PureISCSIDriverTestCase(test.TestCase):
|
||||||
self.assertFalse(self.array.list_host_connections.called)
|
self.assertFalse(self.array.list_host_connections.called)
|
||||||
self.assertFalse(self.array.delete_host.called)
|
self.assertFalse(self.array.delete_host.called)
|
||||||
|
|
||||||
def test_get_volume_stats(self):
|
@mock.patch(DRIVER_OBJ + "._get_provisioned_space", autospec=True)
|
||||||
|
def test_get_volume_stats(self, mock_space):
|
||||||
|
mock_space.return_value = PROVISIONED_CAPACITY * units.Gi
|
||||||
self.assertEqual(self.driver.get_volume_stats(), {})
|
self.assertEqual(self.driver.get_volume_stats(), {})
|
||||||
self.array.get.return_value = SPACE_INFO
|
self.array.get.return_value = SPACE_INFO
|
||||||
result = {"volume_backend_name": VOLUME_BACKEND_NAME,
|
result = {"volume_backend_name": VOLUME_BACKEND_NAME,
|
||||||
"vendor_name": "Pure Storage",
|
"vendor_name": "Pure Storage",
|
||||||
"driver_version": self.driver.VERSION,
|
"driver_version": self.driver.VERSION,
|
||||||
"storage_protocol": "iSCSI",
|
"storage_protocol": "iSCSI",
|
||||||
"total_capacity_gb": TOTAL_SPACE,
|
"total_capacity_gb": TOTAL_CAPACITY,
|
||||||
"free_capacity_gb": FREE_SPACE,
|
"free_capacity_gb": TOTAL_CAPACITY - USED_SPACE,
|
||||||
"reserved_percentage": 0,
|
"reserved_percentage": 0,
|
||||||
"consistencygroup_support": True
|
"consistencygroup_support": True,
|
||||||
|
"thin_provisioning_support": True,
|
||||||
|
"provisioned_capacity": PROVISIONED_CAPACITY,
|
||||||
|
"max_over_subscription_ratio": (PROVISIONED_CAPACITY /
|
||||||
|
USED_SPACE)
|
||||||
|
}
|
||||||
|
real_result = self.driver.get_volume_stats(refresh=True)
|
||||||
|
self.assertDictMatch(result, real_result)
|
||||||
|
self.assertDictMatch(result, self.driver._stats)
|
||||||
|
|
||||||
|
@mock.patch(DRIVER_OBJ + "._get_provisioned_space", autospec=True)
|
||||||
|
def test_get_volume_stats_empty_array(self, mock_space):
|
||||||
|
mock_space.return_value = PROVISIONED_CAPACITY * units.Gi
|
||||||
|
self.assertEqual(self.driver.get_volume_stats(), {})
|
||||||
|
self.array.get.return_value = SPACE_INFO_EMPTY
|
||||||
|
result = {"volume_backend_name": VOLUME_BACKEND_NAME,
|
||||||
|
"vendor_name": "Pure Storage",
|
||||||
|
"driver_version": self.driver.VERSION,
|
||||||
|
"storage_protocol": "iSCSI",
|
||||||
|
"total_capacity_gb": TOTAL_CAPACITY,
|
||||||
|
"free_capacity_gb": TOTAL_CAPACITY,
|
||||||
|
"reserved_percentage": 0,
|
||||||
|
"consistencygroup_support": True,
|
||||||
|
"thin_provisioning_support": True,
|
||||||
|
"provisioned_capacity": PROVISIONED_CAPACITY,
|
||||||
|
"max_over_subscription_ratio": DEFAULT_OVER_SUBSCRIPTION
|
||||||
|
}
|
||||||
|
real_result = self.driver.get_volume_stats(refresh=True)
|
||||||
|
self.assertDictMatch(result, real_result)
|
||||||
|
self.assertDictMatch(result, self.driver._stats)
|
||||||
|
|
||||||
|
@mock.patch(DRIVER_OBJ + "._get_provisioned_space", autospec=True)
|
||||||
|
def test_get_volume_stats_nothing_provisioned(self, mock_space):
|
||||||
|
mock_space.return_value = 0
|
||||||
|
self.assertEqual(self.driver.get_volume_stats(), {})
|
||||||
|
self.array.get.return_value = SPACE_INFO
|
||||||
|
result = {"volume_backend_name": VOLUME_BACKEND_NAME,
|
||||||
|
"vendor_name": "Pure Storage",
|
||||||
|
"driver_version": self.driver.VERSION,
|
||||||
|
"storage_protocol": "iSCSI",
|
||||||
|
"total_capacity_gb": TOTAL_CAPACITY,
|
||||||
|
"free_capacity_gb": TOTAL_CAPACITY - USED_SPACE,
|
||||||
|
"reserved_percentage": 0,
|
||||||
|
"consistencygroup_support": True,
|
||||||
|
"thin_provisioning_support": True,
|
||||||
|
"provisioned_capacity": 0,
|
||||||
|
"max_over_subscription_ratio": DEFAULT_OVER_SUBSCRIPTION
|
||||||
}
|
}
|
||||||
real_result = self.driver.get_volume_stats(refresh=True)
|
real_result = self.driver.get_volume_stats(refresh=True)
|
||||||
self.assertDictMatch(result, real_result)
|
self.assertDictMatch(result, real_result)
|
||||||
|
|
|
@ -99,7 +99,7 @@ def _generate_purity_host_name(name):
|
||||||
class PureISCSIDriver(san.SanISCSIDriver):
|
class PureISCSIDriver(san.SanISCSIDriver):
|
||||||
"""Performs volume management on Pure Storage FlashArray."""
|
"""Performs volume management on Pure Storage FlashArray."""
|
||||||
|
|
||||||
VERSION = "2.0.3"
|
VERSION = "2.0.4"
|
||||||
|
|
||||||
SUPPORTED_REST_API_VERSIONS = ['1.2', '1.3', '1.4']
|
SUPPORTED_REST_API_VERSIONS = ['1.2', '1.3', '1.4']
|
||||||
|
|
||||||
|
@ -382,19 +382,38 @@ class PureISCSIDriver(san.SanISCSIDriver):
|
||||||
def _update_stats(self):
|
def _update_stats(self):
|
||||||
"""Set self._stats with relevant information."""
|
"""Set self._stats with relevant information."""
|
||||||
info = self._array.get(space=True)
|
info = self._array.get(space=True)
|
||||||
total = float(info["capacity"]) / units.Gi
|
total_capacity = float(info["capacity"]) / units.Gi
|
||||||
free = float(info["capacity"] - info["total"]) / units.Gi
|
used_space = float(info["total"]) / units.Gi
|
||||||
|
free_space = float(total_capacity - used_space)
|
||||||
|
provisioned_space = float(self._get_provisioned_space()) / units.Gi
|
||||||
|
# If array is empty we can not calculate a max oversubscription ratio.
|
||||||
|
# In this case we choose 20 as a default value for the ratio. Once
|
||||||
|
# some volumes are actually created and some data is stored on the
|
||||||
|
# array a much more accurate number will be presented based on current
|
||||||
|
# usage.
|
||||||
|
if used_space == 0 or provisioned_space == 0:
|
||||||
|
thin_provisioning = 20
|
||||||
|
else:
|
||||||
|
thin_provisioning = provisioned_space / used_space
|
||||||
data = {"volume_backend_name": self._backend_name,
|
data = {"volume_backend_name": self._backend_name,
|
||||||
"vendor_name": "Pure Storage",
|
"vendor_name": "Pure Storage",
|
||||||
"driver_version": self.VERSION,
|
"driver_version": self.VERSION,
|
||||||
"storage_protocol": "iSCSI",
|
"storage_protocol": "iSCSI",
|
||||||
"total_capacity_gb": total,
|
"total_capacity_gb": total_capacity,
|
||||||
"free_capacity_gb": free,
|
"free_capacity_gb": free_space,
|
||||||
"reserved_percentage": 0,
|
"reserved_percentage": 0,
|
||||||
"consistencygroup_support": True
|
"consistencygroup_support": True,
|
||||||
|
"thin_provisioning_support": True,
|
||||||
|
"provisioned_capacity": provisioned_space,
|
||||||
|
"max_over_subscription_ratio": thin_provisioning
|
||||||
}
|
}
|
||||||
self._stats = data
|
self._stats = data
|
||||||
|
|
||||||
|
def _get_provisioned_space(self):
|
||||||
|
"""Sum up provisioned size of all volumes on array"""
|
||||||
|
volumes = self._array.list_volumes(pending=True)
|
||||||
|
return sum(item["size"] for item in volumes)
|
||||||
|
|
||||||
def extend_volume(self, volume, new_size):
|
def extend_volume(self, volume, new_size):
|
||||||
"""Extend volume to new_size."""
|
"""Extend volume to new_size."""
|
||||||
LOG.debug("Enter PureISCSIDriver.extend_volume.")
|
LOG.debug("Enter PureISCSIDriver.extend_volume.")
|
||||||
|
|
Loading…
Reference in New Issue