Merge "Fix and unify capacity calculations" into stable/xena
This commit is contained in:
commit
73d1473f66
|
@ -17,11 +17,10 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
import math
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from cinder.scheduler import filters
|
from cinder.scheduler import filters
|
||||||
|
from cinder import utils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -103,10 +102,6 @@ class CapacityFilter(filters.BaseBackendFilter):
|
||||||
"grouping_name": backend_state.backend_id})
|
"grouping_name": backend_state.backend_id})
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Calculate how much free space is left after taking into account
|
|
||||||
# the reserved space.
|
|
||||||
free = free_space - math.floor(total * reserved)
|
|
||||||
|
|
||||||
# NOTE(xyang): If 'provisioning:type' is 'thick' in extra_specs,
|
# NOTE(xyang): If 'provisioning:type' is 'thick' in extra_specs,
|
||||||
# we will not use max_over_subscription_ratio and
|
# we will not use max_over_subscription_ratio and
|
||||||
# provisioned_capacity_gb to determine whether a volume can be
|
# provisioned_capacity_gb to determine whether a volume can be
|
||||||
|
@ -118,18 +113,45 @@ class CapacityFilter(filters.BaseBackendFilter):
|
||||||
if provision_type == 'thick':
|
if provision_type == 'thick':
|
||||||
thin = False
|
thin = False
|
||||||
|
|
||||||
|
thin_support = backend_state.thin_provisioning_support
|
||||||
|
if thin_support:
|
||||||
|
max_over_subscription_ratio = (
|
||||||
|
backend_state.max_over_subscription_ratio
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
max_over_subscription_ratio = 1
|
||||||
|
|
||||||
|
# NOTE(hemna): this takes into consideration all major factors
|
||||||
|
# including reserved space, free_space (reported by driver),
|
||||||
|
# and over subscription ratio.
|
||||||
|
factors = utils.calculate_capacity_factors(
|
||||||
|
total_space,
|
||||||
|
free_space,
|
||||||
|
backend_state.provisioned_capacity_gb,
|
||||||
|
thin_support,
|
||||||
|
max_over_subscription_ratio,
|
||||||
|
backend_state.reserved_percentage,
|
||||||
|
thin
|
||||||
|
)
|
||||||
|
virtual_free_space = factors["virtual_free_capacity"]
|
||||||
|
LOG.debug("Storage Capacity factors %s", factors)
|
||||||
|
|
||||||
msg_args = {"grouping_name": backend_state.backend_id,
|
msg_args = {"grouping_name": backend_state.backend_id,
|
||||||
"grouping": grouping,
|
"grouping": grouping,
|
||||||
"requested": requested_size,
|
"requested": requested_size,
|
||||||
"available": free}
|
"available": virtual_free_space}
|
||||||
|
|
||||||
# Only evaluate using max_over_subscription_ratio if
|
# Only evaluate using max_over_subscription_ratio if
|
||||||
# thin_provisioning_support is True. Check if the ratio of
|
# thin_provisioning_support is True. Check if the ratio of
|
||||||
# provisioned capacity over total capacity has exceeded over
|
# provisioned capacity over total capacity has exceeded over
|
||||||
# subscription ratio.
|
# subscription ratio.
|
||||||
if (thin and backend_state.thin_provisioning_support and
|
if (thin and backend_state.thin_provisioning_support and
|
||||||
backend_state.max_over_subscription_ratio >= 1):
|
backend_state.max_over_subscription_ratio >= 1):
|
||||||
provisioned_ratio = ((backend_state.provisioned_capacity_gb +
|
provisioned_ratio = (
|
||||||
requested_size) / total)
|
(backend_state.provisioned_capacity_gb + requested_size) / (
|
||||||
|
factors["total_available_capacity"]
|
||||||
|
)
|
||||||
|
)
|
||||||
LOG.debug("Checking provisioning for request of %s GB. "
|
LOG.debug("Checking provisioning for request of %s GB. "
|
||||||
"Backend: %s", requested_size, backend_state)
|
"Backend: %s", requested_size, backend_state)
|
||||||
if provisioned_ratio > backend_state.max_over_subscription_ratio:
|
if provisioned_ratio > backend_state.max_over_subscription_ratio:
|
||||||
|
@ -149,14 +171,12 @@ class CapacityFilter(filters.BaseBackendFilter):
|
||||||
else:
|
else:
|
||||||
# Thin provisioning is enabled and projected over-subscription
|
# Thin provisioning is enabled and projected over-subscription
|
||||||
# ratio does not exceed max_over_subscription_ratio. The host
|
# ratio does not exceed max_over_subscription_ratio. The host
|
||||||
# passes if "adjusted" free virtual capacity is enough to
|
# passes if virtual free capacity is enough to
|
||||||
# accommodate the volume. Adjusted free virtual capacity is
|
# accommodate the volume. Adjusted free virtual capacity is
|
||||||
# the currently available free capacity (taking into account
|
# the currently available free capacity (taking into account
|
||||||
# of reserved space) which we can over-subscribe.
|
# of reserved space) which we can over-subscribe.
|
||||||
adjusted_free_virtual = (
|
msg_args["available"] = virtual_free_space
|
||||||
free * backend_state.max_over_subscription_ratio)
|
res = virtual_free_space >= requested_size
|
||||||
msg_args["available"] = adjusted_free_virtual
|
|
||||||
res = adjusted_free_virtual >= requested_size
|
|
||||||
if not res:
|
if not res:
|
||||||
LOG.warning("Insufficient free virtual space "
|
LOG.warning("Insufficient free virtual space "
|
||||||
"(%(available)sGB) to accommodate thin "
|
"(%(available)sGB) to accommodate thin "
|
||||||
|
@ -179,7 +199,7 @@ class CapacityFilter(filters.BaseBackendFilter):
|
||||||
"grouping_name": backend_state.backend_id})
|
"grouping_name": backend_state.backend_id})
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if free < requested_size:
|
if virtual_free_space < requested_size:
|
||||||
LOG.warning("Insufficient free space for volume creation "
|
LOG.warning("Insufficient free space for volume creation "
|
||||||
"on %(grouping)s %(grouping_name)s (requested / "
|
"on %(grouping)s %(grouping_name)s (requested / "
|
||||||
"avail): %(requested)s/%(available)s",
|
"avail): %(requested)s/%(available)s",
|
||||||
|
|
|
@ -114,7 +114,7 @@ class CapacityWeigherTestCase(test.TestCase):
|
||||||
{'volume_type': {'extra_specs': {'provisioning:type': 'thin'}},
|
{'volume_type': {'extra_specs': {'provisioning:type': 'thin'}},
|
||||||
'winner': 'host4'},
|
'winner': 'host4'},
|
||||||
{'volume_type': {'extra_specs': {'provisioning:type': 'thick'}},
|
{'volume_type': {'extra_specs': {'provisioning:type': 'thick'}},
|
||||||
'winner': 'host2'},
|
'winner': 'host4'},
|
||||||
{'volume_type': {'extra_specs': {}},
|
{'volume_type': {'extra_specs': {}},
|
||||||
'winner': 'host4'},
|
'winner': 'host4'},
|
||||||
{'volume_type': {},
|
{'volume_type': {},
|
||||||
|
|
|
@ -99,7 +99,7 @@ class CapacityFilterTestCase(BackendFiltersTestCase):
|
||||||
def test_filter_fails(self, _mock_serv_is_up):
|
def test_filter_fails(self, _mock_serv_is_up):
|
||||||
_mock_serv_is_up.return_value = True
|
_mock_serv_is_up.return_value = True
|
||||||
filt_cls = self.class_map['CapacityFilter']()
|
filt_cls = self.class_map['CapacityFilter']()
|
||||||
filter_properties = {'size': 100,
|
filter_properties = {'size': 121,
|
||||||
'request_spec': {'volume_id': fake.VOLUME_ID}}
|
'request_spec': {'volume_id': fake.VOLUME_ID}}
|
||||||
service = {'disabled': False}
|
service = {'disabled': False}
|
||||||
host = fakes.FakeBackendState('host1',
|
host = fakes.FakeBackendState('host1',
|
||||||
|
@ -282,7 +282,7 @@ class CapacityFilterTestCase(BackendFiltersTestCase):
|
||||||
def test_filter_thin_true_passes2(self, _mock_serv_is_up):
|
def test_filter_thin_true_passes2(self, _mock_serv_is_up):
|
||||||
_mock_serv_is_up.return_value = True
|
_mock_serv_is_up.return_value = True
|
||||||
filt_cls = self.class_map['CapacityFilter']()
|
filt_cls = self.class_map['CapacityFilter']()
|
||||||
filter_properties = {'size': 3000,
|
filter_properties = {'size': 2400,
|
||||||
'capabilities:thin_provisioning_support':
|
'capabilities:thin_provisioning_support':
|
||||||
'<is> True',
|
'<is> True',
|
||||||
'capabilities:thick_provisioning_support':
|
'capabilities:thick_provisioning_support':
|
||||||
|
@ -462,7 +462,7 @@ class CapacityFilterTestCase(BackendFiltersTestCase):
|
||||||
def test_filter_reserved_thin_thick_true_fails(self, _mock_serv_is_up):
|
def test_filter_reserved_thin_thick_true_fails(self, _mock_serv_is_up):
|
||||||
_mock_serv_is_up.return_value = True
|
_mock_serv_is_up.return_value = True
|
||||||
filt_cls = self.class_map['CapacityFilter']()
|
filt_cls = self.class_map['CapacityFilter']()
|
||||||
filter_properties = {'size': 100,
|
filter_properties = {'size': 151,
|
||||||
'capabilities:thin_provisioning_support':
|
'capabilities:thin_provisioning_support':
|
||||||
'<is> True',
|
'<is> True',
|
||||||
'capabilities:thick_provisioning_support':
|
'capabilities:thick_provisioning_support':
|
||||||
|
|
|
@ -1029,7 +1029,7 @@ class HostManagerTestCase(test.TestCase):
|
||||||
"free": 18.01,
|
"free": 18.01,
|
||||||
"allocated": 2.0,
|
"allocated": 2.0,
|
||||||
"provisioned": 2.0,
|
"provisioned": 2.0,
|
||||||
"virtual_free": 37.02,
|
"virtual_free": 36.02,
|
||||||
"reported_at": 40000},
|
"reported_at": 40000},
|
||||||
{"name_to_id": 'host1@backend1',
|
{"name_to_id": 'host1@backend1',
|
||||||
"type": "backend",
|
"type": "backend",
|
||||||
|
@ -1037,7 +1037,7 @@ class HostManagerTestCase(test.TestCase):
|
||||||
"free": 46.02,
|
"free": 46.02,
|
||||||
"allocated": 4.0,
|
"allocated": 4.0,
|
||||||
"provisioned": 4.0,
|
"provisioned": 4.0,
|
||||||
"virtual_free": 64.03,
|
"virtual_free": 63.03,
|
||||||
"reported_at": 40000}]
|
"reported_at": 40000}]
|
||||||
|
|
||||||
expected2 = [
|
expected2 = [
|
||||||
|
@ -1055,7 +1055,7 @@ class HostManagerTestCase(test.TestCase):
|
||||||
"free": 46.02,
|
"free": 46.02,
|
||||||
"allocated": 4.0,
|
"allocated": 4.0,
|
||||||
"provisioned": 4.0,
|
"provisioned": 4.0,
|
||||||
"virtual_free": 95.04,
|
"virtual_free": 94.04,
|
||||||
"reported_at": 40000}]
|
"reported_at": 40000}]
|
||||||
|
|
||||||
def sort_func(data):
|
def sort_func(data):
|
||||||
|
|
|
@ -1083,10 +1083,10 @@ class TestCalculateVirtualFree(test.TestCase):
|
||||||
'is_thin_lun': False, 'expected': 27.01},
|
'is_thin_lun': False, 'expected': 27.01},
|
||||||
{'total': 20.01, 'free': 18.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
{'total': 20.01, 'free': 18.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
||||||
'thin_support': True, 'thick_support': False,
|
'thin_support': True, 'thick_support': False,
|
||||||
'is_thin_lun': True, 'expected': 37.02},
|
'is_thin_lun': True, 'expected': 36.02},
|
||||||
{'total': 20.01, 'free': 18.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
{'total': 20.01, 'free': 18.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
||||||
'thin_support': True, 'thick_support': True,
|
'thin_support': True, 'thick_support': True,
|
||||||
'is_thin_lun': True, 'expected': 37.02},
|
'is_thin_lun': True, 'expected': 36.02},
|
||||||
{'total': 30.01, 'free': 28.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
{'total': 30.01, 'free': 28.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
||||||
'thin_support': True, 'thick_support': True,
|
'thin_support': True, 'thick_support': True,
|
||||||
'is_thin_lun': False, 'expected': 27.01},
|
'is_thin_lun': False, 'expected': 27.01},
|
||||||
|
@ -1114,6 +1114,98 @@ class TestCalculateVirtualFree(test.TestCase):
|
||||||
|
|
||||||
self.assertEqual(expected, free_capacity)
|
self.assertEqual(expected, free_capacity)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
{'total': 30.01, 'free': 28.01, 'provisioned': 2.0, 'max_ratio': 1.0,
|
||||||
|
'thin_support': False, 'thick_support': True,
|
||||||
|
'is_thin_lun': False, 'reserved_percentage': 5,
|
||||||
|
'expected_total_capacity': 30.01,
|
||||||
|
'expected_reserved_capacity': 1,
|
||||||
|
'expected_free_capacity': 28.01,
|
||||||
|
'expected_total_available_capacity': 29.01,
|
||||||
|
'expected_virtual_free': 27.01,
|
||||||
|
'expected_free_percent': 93.11,
|
||||||
|
'expected_provisioned_type': 'thick',
|
||||||
|
'expected_provisioned_ratio': 0.07},
|
||||||
|
{'total': 20.01, 'free': 18.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
||||||
|
'thin_support': True, 'thick_support': False,
|
||||||
|
'is_thin_lun': True, 'reserved_percentage': 10,
|
||||||
|
'expected_total_capacity': 20.01,
|
||||||
|
'expected_reserved_capacity': 2,
|
||||||
|
'expected_free_capacity': 18.01,
|
||||||
|
'expected_total_available_capacity': 36.02,
|
||||||
|
'expected_virtual_free': 34.02,
|
||||||
|
'expected_free_percent': 94.45,
|
||||||
|
'expected_provisioned_type': 'thin',
|
||||||
|
'expected_provisioned_ratio': 0.06},
|
||||||
|
{'total': 20.01, 'free': 18.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
||||||
|
'thin_support': True, 'thick_support': True,
|
||||||
|
'is_thin_lun': True, 'reserved_percentage': 20,
|
||||||
|
'expected_total_capacity': 20.01,
|
||||||
|
'expected_reserved_capacity': 4,
|
||||||
|
'expected_free_capacity': 18.01,
|
||||||
|
'expected_total_available_capacity': 32.02,
|
||||||
|
'expected_virtual_free': 30.02,
|
||||||
|
'expected_free_percent': 93.75,
|
||||||
|
'expected_provisioned_type': 'thin',
|
||||||
|
'expected_provisioned_ratio': 0.06},
|
||||||
|
{'total': 30.01, 'free': 28.01, 'provisioned': 2.0, 'max_ratio': 2.0,
|
||||||
|
'thin_support': True, 'thick_support': True,
|
||||||
|
'is_thin_lun': False, 'reserved_percentage': 10,
|
||||||
|
'expected_total_capacity': 30.01,
|
||||||
|
'expected_reserved_capacity': 3,
|
||||||
|
'expected_free_capacity': 28.01,
|
||||||
|
'expected_total_available_capacity': 27.01,
|
||||||
|
'expected_virtual_free': 25.01,
|
||||||
|
'expected_free_percent': 92.6,
|
||||||
|
'expected_provisioned_type': 'thick',
|
||||||
|
'expected_provisioned_ratio': 0.07},
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_utils_calculate_capacity_factors(
|
||||||
|
self, total, free, provisioned, max_ratio, thin_support,
|
||||||
|
thick_support, is_thin_lun, reserved_percentage,
|
||||||
|
expected_total_capacity,
|
||||||
|
expected_reserved_capacity,
|
||||||
|
expected_free_capacity,
|
||||||
|
expected_total_available_capacity,
|
||||||
|
expected_virtual_free,
|
||||||
|
expected_free_percent,
|
||||||
|
expected_provisioned_type,
|
||||||
|
expected_provisioned_ratio):
|
||||||
|
host_stat = {'total_capacity_gb': total,
|
||||||
|
'free_capacity_gb': free,
|
||||||
|
'provisioned_capacity_gb': provisioned,
|
||||||
|
'max_over_subscription_ratio': max_ratio,
|
||||||
|
'thin_provisioning_support': thin_support,
|
||||||
|
'thick_provisioning_support': thick_support,
|
||||||
|
'reserved_percentage': reserved_percentage}
|
||||||
|
|
||||||
|
factors = utils.calculate_capacity_factors(
|
||||||
|
host_stat['total_capacity_gb'],
|
||||||
|
host_stat['free_capacity_gb'],
|
||||||
|
host_stat['provisioned_capacity_gb'],
|
||||||
|
host_stat['thin_provisioning_support'],
|
||||||
|
host_stat['max_over_subscription_ratio'],
|
||||||
|
host_stat['reserved_percentage'],
|
||||||
|
is_thin_lun)
|
||||||
|
|
||||||
|
self.assertEqual(expected_total_capacity,
|
||||||
|
factors['total_capacity'])
|
||||||
|
self.assertEqual(expected_reserved_capacity,
|
||||||
|
factors['reserved_capacity'])
|
||||||
|
self.assertEqual(expected_free_capacity,
|
||||||
|
factors['free_capacity'])
|
||||||
|
self.assertEqual(expected_total_available_capacity,
|
||||||
|
factors['total_available_capacity'])
|
||||||
|
self.assertEqual(expected_virtual_free,
|
||||||
|
factors['virtual_free_capacity'])
|
||||||
|
self.assertEqual(expected_free_percent,
|
||||||
|
factors['free_percent'])
|
||||||
|
self.assertEqual(expected_provisioned_type,
|
||||||
|
factors['provisioned_type'])
|
||||||
|
self.assertEqual(expected_provisioned_ratio,
|
||||||
|
factors['provisioned_ratio'])
|
||||||
|
|
||||||
|
|
||||||
class Comparable(utils.ComparableMixin):
|
class Comparable(utils.ComparableMixin):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
|
|
130
cinder/utils.py
130
cinder/utils.py
|
@ -706,14 +706,118 @@ def build_or_str(elements: Union[None, str, Iterable[str]],
|
||||||
return elements
|
return elements
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_capacity_factors(total_capacity: float,
|
||||||
|
free_capacity: float,
|
||||||
|
provisioned_capacity: float,
|
||||||
|
thin_provisioning_support: bool,
|
||||||
|
max_over_subscription_ratio: float,
|
||||||
|
reserved_percentage: int,
|
||||||
|
thin: bool) -> dict:
|
||||||
|
"""Create the various capacity factors of the a particular backend.
|
||||||
|
|
||||||
|
Based off of definition of terms
|
||||||
|
cinder-specs/specs/queens/provisioning-improvements.html
|
||||||
|
Description of factors calculated where units of gb are Gibibytes.
|
||||||
|
reserved_capacity - The amount of space reserved from the total_capacity
|
||||||
|
as reported by the backend.
|
||||||
|
total_reserved_available_capacity - The total capacity minus reserved
|
||||||
|
capacity
|
||||||
|
total_available_capacity - The total capacity available to cinder
|
||||||
|
calculated from total_reserved_available_capacity (for thick) OR
|
||||||
|
for thin total_reserved_available_capacity max_over_subscription_ratio
|
||||||
|
calculated_free_capacity - total_available_capacity - provisioned_capacity
|
||||||
|
virtual_free_capacity - The calculated free capacity available to cinder
|
||||||
|
to allocate new storage.
|
||||||
|
For thin: calculated_free_capacity
|
||||||
|
For thick: the reported free_capacity can be less than the calculated
|
||||||
|
capacity, so we use free_capacity - reserved_capacity.
|
||||||
|
|
||||||
|
free_percent - the percentage of the virtual_free_capacity and
|
||||||
|
total_available_capacity is left over
|
||||||
|
provisioned_ratio - The ratio of provisioned storage to
|
||||||
|
total_available_capacity
|
||||||
|
|
||||||
|
:param total_capacity: The reported total capacity in the backend.
|
||||||
|
:type total_capacity: float
|
||||||
|
:param free_capacity: The free space/capacity as reported by the backend.
|
||||||
|
:type free_capacity: float
|
||||||
|
:param provisioned_capacity: as reported by backend or volume manager from
|
||||||
|
allocated_capacity_gb
|
||||||
|
:type provisioned_capacity: float
|
||||||
|
:param thin_provisioning_support: Is thin provisioning supported?
|
||||||
|
:type thin_provisioning_support: bool
|
||||||
|
:param max_over_subscription_ratio: as reported by the backend
|
||||||
|
:type max_over_subscription_ratio: float
|
||||||
|
:param reserved_percentage: the % amount to reserve as unavailable. 0-100
|
||||||
|
:type reserved_percentage: int, 0-100
|
||||||
|
:param thin: calculate based on thin provisioning if enabled by
|
||||||
|
thin_provisioning_support
|
||||||
|
:type thin: bool
|
||||||
|
:return: A dictionary of all of the capacity factors.
|
||||||
|
:rtype: dict
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
total = float(total_capacity)
|
||||||
|
reserved = float(reserved_percentage) / 100
|
||||||
|
reserved_capacity = math.floor(total * reserved)
|
||||||
|
total_reserved_available = total - reserved_capacity
|
||||||
|
|
||||||
|
if thin and thin_provisioning_support:
|
||||||
|
total_available_capacity = (
|
||||||
|
total_reserved_available * max_over_subscription_ratio
|
||||||
|
)
|
||||||
|
calculated_free = total_available_capacity - provisioned_capacity
|
||||||
|
virtual_free = calculated_free
|
||||||
|
provisioned_type = 'thin'
|
||||||
|
else:
|
||||||
|
# Calculate how much free space is left after taking into
|
||||||
|
# account the reserved space.
|
||||||
|
total_available_capacity = total_reserved_available
|
||||||
|
calculated_free = total_available_capacity - provisioned_capacity
|
||||||
|
virtual_free = calculated_free
|
||||||
|
if free_capacity < calculated_free:
|
||||||
|
virtual_free = free_capacity
|
||||||
|
|
||||||
|
provisioned_type = 'thick'
|
||||||
|
|
||||||
|
if total_available_capacity:
|
||||||
|
provisioned_ratio = provisioned_capacity / total_available_capacity
|
||||||
|
free_percent = (virtual_free / total_available_capacity) * 100
|
||||||
|
else:
|
||||||
|
provisioned_ratio = 0
|
||||||
|
free_percent = 0
|
||||||
|
|
||||||
|
def _limit(x):
|
||||||
|
"""Limit our floating points to 2 decimal places."""
|
||||||
|
return round(x, 2)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"total_capacity": total,
|
||||||
|
"free_capacity": free_capacity,
|
||||||
|
"reserved_capacity": reserved_capacity,
|
||||||
|
"total_reserved_available_capacity": _limit(total_reserved_available),
|
||||||
|
"max_over_subscription_ratio": (
|
||||||
|
max_over_subscription_ratio if provisioned_type == 'thin' else None
|
||||||
|
),
|
||||||
|
"total_available_capacity": _limit(total_available_capacity),
|
||||||
|
"provisioned_capacity": provisioned_capacity,
|
||||||
|
"calculated_free_capacity": _limit(calculated_free),
|
||||||
|
"virtual_free_capacity": _limit(virtual_free),
|
||||||
|
"free_percent": _limit(free_percent),
|
||||||
|
"provisioned_ratio": _limit(provisioned_ratio),
|
||||||
|
"provisioned_type": provisioned_type
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def calculate_virtual_free_capacity(total_capacity: float,
|
def calculate_virtual_free_capacity(total_capacity: float,
|
||||||
free_capacity: float,
|
free_capacity: float,
|
||||||
provisioned_capacity: float,
|
provisioned_capacity: float,
|
||||||
thin_provisioning_support: bool,
|
thin_provisioning_support: bool,
|
||||||
max_over_subscription_ratio: float,
|
max_over_subscription_ratio: float,
|
||||||
reserved_percentage: float,
|
reserved_percentage: int,
|
||||||
thin: bool) -> float:
|
thin: bool) -> float:
|
||||||
"""Calculate the virtual free capacity based on thin provisioning support.
|
"""Calculate the virtual free capacity based on multiple factors.
|
||||||
|
|
||||||
:param total_capacity: total_capacity_gb of a host_state or pool.
|
:param total_capacity: total_capacity_gb of a host_state or pool.
|
||||||
:param free_capacity: free_capacity_gb of a host_state or pool.
|
:param free_capacity: free_capacity_gb of a host_state or pool.
|
||||||
|
@ -729,18 +833,16 @@ def calculate_virtual_free_capacity(total_capacity: float,
|
||||||
:returns: the calculated virtual free capacity.
|
:returns: the calculated virtual free capacity.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
total = float(total_capacity)
|
factors = calculate_capacity_factors(
|
||||||
reserved = float(reserved_percentage) / 100
|
total_capacity,
|
||||||
|
free_capacity,
|
||||||
if thin and thin_provisioning_support:
|
provisioned_capacity,
|
||||||
free = (total * max_over_subscription_ratio
|
thin_provisioning_support,
|
||||||
- provisioned_capacity
|
max_over_subscription_ratio,
|
||||||
- math.floor(total * reserved))
|
reserved_percentage,
|
||||||
else:
|
thin
|
||||||
# Calculate how much free space is left after taking into
|
)
|
||||||
# account the reserved space.
|
return factors["virtual_free_capacity"]
|
||||||
free = free_capacity - math.floor(total * reserved)
|
|
||||||
return free
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_max_over_subscription_ratio(
|
def calculate_max_over_subscription_ratio(
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
other:
|
||||||
|
- |
|
||||||
|
Unified how cinder calculates the virtual free storage space for a pool.
|
||||||
|
Previously Cinder had 2 different mechanisms for calculating the
|
||||||
|
virtual free storage. Now both the Capacity Filter and the Capacity
|
||||||
|
Weigher use the same mechanism, which is based upon the defined terms in
|
||||||
|
https://specs.openstack.org/openstack/cinder-specs/specs/queens/provisioning-improvements.html
|
Loading…
Reference in New Issue