diff --git a/manila/scheduler/filters/capacity.py b/manila/scheduler/filters/capacity.py index 4f694557d5..119c563f61 100644 --- a/manila/scheduler/filters/capacity.py +++ b/manila/scheduler/filters/capacity.py @@ -24,6 +24,7 @@ from oslo_log import log from manila.i18n import _LE from manila.i18n import _LW from manila.scheduler.filters import base_host +from manila.scheduler import utils LOG = log.getLogger(__name__) @@ -77,14 +78,19 @@ class CapacityFilter(base_host.BaseHostFilter): "on host %(host)s (requested / avail): " "%(requested)s/%(available)s", msg_args) + share_type = filter_properties.get('share_type', {}) + use_thin_logic = utils.use_thin_logic(share_type) + thin_provisioning = utils.thin_provisioning( + host_state.thin_provisioning) + # NOTE(xyang): Only evaluate using max_over_subscription_ratio - # if thin_provisioning is True. Check if the ratio of - # provisioned capacity over total capacity would exceed + # if use_thin_logic and thin_provisioning are True. Check if the + # ratio of provisioned capacity over total capacity would exceed # subscription ratio. # If max_over_subscription_ratio = 1, the provisioned_ratio # should still be limited by the max_over_subscription_ratio; # otherwise, it could result in infinite provisioning. - if (host_state.thin_provisioning and + if (use_thin_logic and thin_provisioning and host_state.max_over_subscription_ratio >= 1): provisioned_ratio = ((host_state.provisioned_capacity_gb + share_size) / total) @@ -105,7 +111,8 @@ class CapacityFilter(base_host.BaseHostFilter): adjusted_free_virtual = ( free * host_state.max_over_subscription_ratio) return adjusted_free_virtual >= share_size - elif host_state.thin_provisioning: + elif (use_thin_logic and thin_provisioning and + host_state.max_over_subscription_ratio < 1): LOG.error(_LE("Invalid max_over_subscription_ratio: %(ratio)s. " "Valid value should be >= 1."), {"ratio": host_state.max_over_subscription_ratio}) diff --git a/manila/scheduler/utils.py b/manila/scheduler/utils.py index 2a24fcc1dd..87309f10bb 100644 --- a/manila/scheduler/utils.py +++ b/manila/scheduler/utils.py @@ -1,4 +1,6 @@ # Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# Copyright (c) 2016 EMC Corporation +# # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -13,6 +15,10 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_utils import strutils + +from manila.scheduler.filters import extra_specs_ops + def generate_stats(host_state, properties): """Generates statistics from host and share data.""" @@ -61,3 +67,47 @@ def generate_stats(host_state, properties): } return stats + + +def use_thin_logic(share_type): + # NOTE(xyang): To preserve the existing behavior, we use thin logic + # to evaluate in two cases: + # 1) 'thin_provisioning' is not set in extra specs (This is for + # backward compatibility. If not set, the scheduler behaves + # the same as before this bug fix). + # 2) 'thin_provisioning' is set in extra specs and it is + # ' True' or 'True'. + # Otherwise we use the thick logic to evaluate. + use_thin_logic = True + thin_spec = None + try: + thin_spec = share_type.get('extra_specs', {}).get( + 'thin_provisioning') + if thin_spec is None: + thin_spec = share_type.get('extra_specs', {}).get( + 'capabilities:thin_provisioning') + # NOTE(xyang) 'use_thin_logic' and 'thin_provisioning' are NOT + # the same thing. The first purpose of "use_thin_logic" is to + # preserve the existing scheduler behavior if 'thin_provisioning' + # is NOT in extra_specs (if thin_spec is None, use_thin_logic + # should be True). The second purpose of 'use_thin_logic' + # is to honor 'thin_provisioning' if it is in extra specs (if + # thin_spec is set to True, use_thin_logic should be True; if + # thin_spec is set to False, use_thin_logic should be False). + use_thin_logic = strutils.bool_from_string( + thin_spec, strict=True) if thin_spec is not None else True + except ValueError: + # Check if the value of thin_spec is ' True'. + if thin_spec is not None and not extra_specs_ops.match( + True, thin_spec): + use_thin_logic = False + return use_thin_logic + + +def thin_provisioning(host_state_thin_provisioning): + # NOTE(xyang): host_state_thin_provisioning is reported by driver. + # It can be either bool (True or False) or + # list ([True, False], [True], [False]). + thin_capability = [host_state_thin_provisioning] if not isinstance( + host_state_thin_provisioning, list) else host_state_thin_provisioning + return True in thin_capability diff --git a/manila/scheduler/weighers/capacity.py b/manila/scheduler/weighers/capacity.py index 6943e10156..847a6f8608 100644 --- a/manila/scheduler/weighers/capacity.py +++ b/manila/scheduler/weighers/capacity.py @@ -31,7 +31,7 @@ import math from oslo_config import cfg - +from manila.scheduler import utils from manila.scheduler.weighers import base_host capacity_weight_opts = [ @@ -63,7 +63,13 @@ class CapacityWeigher(base_host.BaseHostWeigher): free = float('inf') else: total = float(total_space) - if host_state.thin_provisioning: + + share_type = weight_properties.get('share_type', {}) + use_thin_logic = utils.use_thin_logic(share_type) + thin_provisioning = utils.thin_provisioning( + host_state.thin_provisioning) + + if use_thin_logic and thin_provisioning: # NOTE(xyang): Calculate virtual free capacity for thin # provisioning. free = math.floor( diff --git a/manila/tests/scheduler/fakes.py b/manila/tests/scheduler/fakes.py index 12c339aa24..f4431c44f9 100644 --- a/manila/tests/scheduler/fakes.py +++ b/manila/tests/scheduler/fakes.py @@ -212,7 +212,7 @@ class FakeHostManager(host_manager.HostManager): 'allocated_capacity_gb': 256, 'provisioned_capacity_gb': 256, 'max_over_subscription_ratio': 2.0, - 'thin_provisioning': False, + 'thin_provisioning': [False], 'consistency_group_support': 'host', 'reserved_percentage': 0, 'snapshot_support': True, @@ -223,7 +223,7 @@ class FakeHostManager(host_manager.HostManager): 'allocated_capacity_gb': 1848, 'provisioned_capacity_gb': 1848, 'max_over_subscription_ratio': 1.0, - 'thin_provisioning': True, + 'thin_provisioning': [True], 'reserved_percentage': 5, 'timestamp': None, 'snapshot_support': True, @@ -235,7 +235,7 @@ class FakeHostManager(host_manager.HostManager): 'allocated_capacity_gb': 1548, 'provisioned_capacity_gb': 1548, 'max_over_subscription_ratio': 1.5, - 'thin_provisioning': True, + 'thin_provisioning': [True, False], 'reserved_percentage': 5, 'timestamp': None, 'snapshot_support': True, diff --git a/manila/tests/scheduler/filters/test_capacity.py b/manila/tests/scheduler/filters/test_capacity.py index a88df8c67c..4532ad2d96 100644 --- a/manila/tests/scheduler/filters/test_capacity.py +++ b/manila/tests/scheduler/filters/test_capacity.py @@ -121,31 +121,76 @@ class HostFiltersTestCase(test.TestCase): @ddt.data( {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 200, 'provisioned': 500, - 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'capabilities:thin_provisioning'}, {'size': 3000, 'cap_thin': ' True', 'total': 500, 'free': 200, 'provisioned': 7000, - 'max_ratio': 20, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 20, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'thin_provisioning'}, {'size': 100, 'cap_thin': ' False', 'total': 500, 'free': 200, 'provisioned': 300, - 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': False}, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': False, + 'cap_thin_key': 'capabilities:thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 200, 'provisioned': 400, - 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 125, 'provisioned': 400, - 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'capabilities:thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 80, 'provisioned': 600, - 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 100, 'provisioned': 400, - 'max_ratio': 2.0, 'reserved': 0, 'thin_prov': True}) + 'max_ratio': 2.0, 'reserved': 0, 'thin_prov': True, + 'cap_thin_key': 'capabilities:thin_provisioning'}, + {'size': 100, 'cap_thin': ' True', + 'total': 500, 'free': 200, 'provisioned': 500, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': [True, False], + 'cap_thin_key': 'thin_provisioning'}, + {'size': 3000, 'cap_thin': ' True', + 'total': 500, 'free': 200, 'provisioned': 7000, + 'max_ratio': 20, 'reserved': 5, 'thin_prov': [True], + 'cap_thin_key': 'capabilities:thin_provisioning'}, + {'size': 100, 'cap_thin': ' False', + 'total': 500, 'free': 200, 'provisioned': 300, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': [False], + 'cap_thin_key': 'thin_provisioning'}, + {'size': 100, 'cap_thin': 'True', + 'total': 500, 'free': 200, 'provisioned': 400, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': [False, True], + 'cap_thin_key': 'capabilities:thin_provisioning'}, + {'size': 100, 'cap_thin': 'False', + 'total': 500, 'free': 200, 'provisioned': 300, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': False, + 'cap_thin_key': 'thin_provisioning'}, + {'size': 100, 'cap_thin': 'true', + 'total': 500, 'free': 125, 'provisioned': 400, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': [True, ], + 'cap_thin_key': 'capabilities:thin_provisioning'}, + {'size': 100, 'cap_thin': 'false', + 'total': 500, 'free': 200, 'provisioned': 300, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': [False, ], + 'cap_thin_key': 'thin_provisioning'}, + {'size': 100, 'cap_thin': None, + 'total': 500, 'free': 80, 'provisioned': 600, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': None},) @ddt.unpack def test_filter_thin_passes(self, size, cap_thin, total, free, provisioned, - max_ratio, reserved, thin_prov): + max_ratio, reserved, thin_prov, cap_thin_key): self._stub_service_is_up(True) - filter_properties = {'size': size, - 'capabilities:thin_provisioning': cap_thin} + filter_properties = { + 'size': size, + 'share_type': { + 'extra_specs': { + cap_thin_key: cap_thin, + } + } + } service = {'disabled': False} host = fakes.FakeHostState('host1', {'total_capacity_gb': total, @@ -161,34 +206,80 @@ class HostFiltersTestCase(test.TestCase): @ddt.data( {'size': 200, 'cap_thin': ' True', 'total': 500, 'free': 100, 'provisioned': 400, - 'max_ratio': 0.8, 'reserved': 0, 'thin_prov': True}, + 'max_ratio': 0.8, 'reserved': 0, 'thin_prov': True, + 'cap_thin_key': 'capabilities:thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 200, 'provisioned': 700, - 'max_ratio': 1.5, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 1.5, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'thin_provisioning'}, {'size': 2000, 'cap_thin': ' True', 'total': 500, 'free': 30, 'provisioned': 9000, - 'max_ratio': 20.0, 'reserved': 0, 'thin_prov': True}, + 'max_ratio': 20.0, 'reserved': 0, 'thin_prov': True, + 'cap_thin_key': 'capabilities:thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 100, 'provisioned': 1000, - 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'thin_provisioning'}, {'size': 100, 'cap_thin': ' False', 'total': 500, 'free': 100, 'provisioned': 400, - 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': False}, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': False, + 'cap_thin_key': 'capabilities:thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 0, 'provisioned': 800, - 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'thin_provisioning'}, {'size': 100, 'cap_thin': ' True', 'total': 500, 'free': 99, 'provisioned': 1000, - 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True}, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'capabilities:thin_provisioning'}, {'size': 400, 'cap_thin': ' True', 'total': 500, 'free': 200, 'provisioned': 600, - 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True}) + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': True, + 'cap_thin_key': 'thin_provisioning'}, + {'size': 200, 'cap_thin': ' True', + 'total': 500, 'free': 100, 'provisioned': 400, + 'max_ratio': 0.8, 'reserved': 0, 'thin_prov': [False, True], + 'cap_thin_key': 'capabilities:thin_provisioning'}, + {'size': 2000, 'cap_thin': ' True', + 'total': 500, 'free': 30, 'provisioned': 9000, + 'max_ratio': 20.0, 'reserved': 0, 'thin_prov': [True], + 'cap_thin_key': 'thin_provisioning'}, + {'size': 100, 'cap_thin': ' False', + 'total': 500, 'free': 100, 'provisioned': 400, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': [False], + 'cap_thin_key': 'thin_provisioning'}, + {'size': 100, 'cap_thin': 'False', + 'total': 500, 'free': 100, 'provisioned': 400, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': False, + 'cap_thin_key': 'capabilities:thin_provisioning'}, + {'size': 100, 'cap_thin': 'True', + 'total': 500, 'free': 0, 'provisioned': 800, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': [False, True], + 'cap_thin_key': 'thin_provisioning'}, + {'size': 100, 'cap_thin': 'true', + 'total': 500, 'free': 99, 'provisioned': 1000, + 'max_ratio': 2.0, 'reserved': 5, 'thin_prov': [True, ], + 'cap_thin_key': 'capabilities:thin_provisioning'}, + {'size': 100, 'cap_thin': 'false', + 'total': 500, 'free': 100, 'provisioned': 400, + 'max_ratio': 1.0, 'reserved': 5, 'thin_prov': [False, ], + 'cap_thin_key': 'thin_provisioning'}, + {'size': 2000, 'cap_thin': None, + 'total': 500, 'free': 30, 'provisioned': 9000, + 'max_ratio': 20.0, 'reserved': 0, 'thin_prov': [True], + 'cap_thin_key': None},) @ddt.unpack def test_filter_thin_fails(self, size, cap_thin, total, free, provisioned, - max_ratio, reserved, thin_prov): + max_ratio, reserved, thin_prov, cap_thin_key): self._stub_service_is_up(True) - filter_properties = {'size': size, - 'capabilities:thin_provisioning': cap_thin} + filter_properties = { + 'size': size, + 'share_type': { + 'extra_specs': { + cap_thin_key: cap_thin, + } + } + } service = {'disabled': False} host = fakes.FakeHostState('host1', {'total_capacity_gb': total, diff --git a/manila/tests/scheduler/test_utils.py b/manila/tests/scheduler/test_utils.py new file mode 100644 index 0000000000..4dcf451059 --- /dev/null +++ b/manila/tests/scheduler/test_utils.py @@ -0,0 +1,64 @@ +# Copyright 2016 EMC Corporation OpenStack Foundation. +# 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. + +""" +Tests For utils. +""" + +import ddt + +from manila.scheduler import utils +from manila import test + + +@ddt.ddt +class UtilsTestCase(test.TestCase): + """Test case for utils.""" + + def setUp(self): + super(UtilsTestCase, self).setUp() + + @ddt.data( + ({'extra_specs': {'thin_provisioning': True}}, True), + ({'extra_specs': {'thin_provisioning': False}}, False), + ({'extra_specs': {'foo': 'bar'}}, True), + ({'foo': 'bar'}, True), + ({'extra_specs': {'thin_provisioning': ' True'}}, + True), + ({'extra_specs': {'thin_provisioning': ' False'}}, + False), + ({'extra_specs': {'thin_provisioning': ' True'}}, + False), + ({'extra_specs': {}}, True), + ({}, True), + ) + @ddt.unpack + def test_use_thin_logic(self, properties, use_thin): + use_thin_logic = utils.use_thin_logic(properties) + self.assertEqual(use_thin, use_thin_logic) + + @ddt.data( + (True, True), + (False, False), + (None, False), + ([True, False], True), + ([True], True), + ([False], False), + ('wrong', False), + ) + @ddt.unpack + def test_thin_provisioning(self, thin_capabilities, thin): + thin_provisioning = utils.thin_provisioning(thin_capabilities) + self.assertEqual(thin, thin_provisioning) diff --git a/manila/tests/scheduler/weighers/test_capacity.py b/manila/tests/scheduler/weighers/test_capacity.py index e01bade9b0..1d4f0813f0 100644 --- a/manila/tests/scheduler/weighers/test_capacity.py +++ b/manila/tests/scheduler/weighers/test_capacity.py @@ -16,6 +16,7 @@ Tests For Capacity Weigher. """ +import ddt import mock from oslo_config import cfg @@ -29,6 +30,7 @@ from manila.tests.scheduler import fakes CONF = cfg.CONF +@ddt.ddt class CapacityWeigherTestCase(test.TestCase): def setUp(self): super(CapacityWeigherTestCase, self).setUp() @@ -61,9 +63,37 @@ class CapacityWeigherTestCase(test.TestCase): # - total * reserved) # Otherwise, use the following formula: # free = math.floor(free_space - total * reserved) - def test_default_of_spreading_first(self): + + @ddt.data( + {'cap_thin': ' True', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': ' False', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host1'}, + {'cap_thin': 'True', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': 'False', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host1'}, + {'cap_thin': 'true', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': 'false', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host1'}, + {'cap_thin': None, + 'cap_thin_key': None, + 'winner': 'host2'}, + ) + @ddt.unpack + def test_default_of_spreading_first(self, cap_thin, cap_thin_key, + winner): hostinfo_list = self._get_all_hosts() + # Results for the 1st test + # {'capabilities:thin_provisioning': ' True'}: # host1: thin_provisioning = False # free_capacity_gb = 1024 # free = math.floor(1024 - 1024 * 0.1) = 921.0 @@ -73,16 +103,16 @@ class CapacityWeigherTestCase(test.TestCase): # free_capacity_gb = 300 # free = math.floor(2048 * 2.0 - 1748 - 2048 * 0.1)=2143.0 # weight = 1.0 - # host3: thin_provisioning = False + # host3: thin_provisioning = [False] # free_capacity_gb = 512 # free = math.floor(256 - 512 * 0)=256.0 # weight = 0.08 - # host4: thin_provisioning = True + # host4: thin_provisioning = [True] # max_over_subscription_ratio = 1.0 # free_capacity_gb = 200 # free = math.floor(2048 * 1.0 - 1848 - 2048 * 0.05) = 97.0 # weight = 0.0 - # host5: thin_provisioning = True + # host5: thin_provisioning = [True, False] # max_over_subscription_ratio = 1.5 # free_capacity_gb = 500 # free = math.floor(2048 * 1.5 - 1548 - 2048 * 0.05) = 1421.0 @@ -92,10 +122,20 @@ class CapacityWeigherTestCase(test.TestCase): # weight = 0.0 # so, host2 should win: - weighed_host = self._get_weighed_host(hostinfo_list) + weight_properties = { + 'size': 1, + 'share_type': { + 'extra_specs': { + cap_thin_key: cap_thin, + } + } + } + weighed_host = self._get_weighed_host( + hostinfo_list, + weight_properties=weight_properties) self.assertEqual(1.0, weighed_host.weight) self.assertEqual( - 'host2', utils.extract_host(weighed_host.obj.host)) + winner, utils.extract_host(weighed_host.obj.host)) def test_unknown_is_last(self): hostinfo_list = self._get_all_hosts() @@ -105,10 +145,38 @@ class CapacityWeigherTestCase(test.TestCase): 'host6', utils.extract_host(last_host.obj.host)) self.assertEqual(0.0, last_host.weight) - def test_capacity_weight_multiplier_negative_1(self): + @ddt.data( + {'cap_thin': ' True', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host4'}, + {'cap_thin': ' False', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': 'True', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host4'}, + {'cap_thin': 'False', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': 'true', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host4'}, + {'cap_thin': 'false', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': None, + 'cap_thin_key': None, + 'winner': 'host4'}, + ) + @ddt.unpack + def test_capacity_weight_multiplier_negative_1(self, cap_thin, + cap_thin_key, + winner): self.flags(capacity_weight_multiplier=-1.0) hostinfo_list = self._get_all_hosts() + # Results for the 1st test + # {'capabilities:thin_provisioning': ' True'}: # host1: thin_provisioning = False # free_capacity_gb = 1024 # free = math.floor(1024 - 1024 * 0.1) = 921.0 @@ -120,18 +188,18 @@ class CapacityWeigherTestCase(test.TestCase): # free = math.floor(2048 * 2.0-1748-2048 * 0.1) = 2143.0 # free * (-1) = -2143.0 # weight = -1.0 - # host3: thin_provisioning = False + # host3: thin_provisioning = [False] # free_capacity_gb = 512 # free = math.floor(256 - 512 * 0) = 256.0 # free * (-1) = -256.0 # weight = -0.08 - # host4: thin_provisioning = True + # host4: thin_provisioning = [True] # max_over_subscription_ratio = 1.0 # free_capacity_gb = 200 # free = math.floor(2048 * 1.0 - 1848 - 2048 * 0.05) = 97.0 # free * (-1) = -97.0 # weight = 0.0 - # host5: thin_provisioning = True + # host5: thin_provisioning = [True, False] # max_over_subscription_ratio = 1.5 # free_capacity_gb = 500 # free = math.floor(2048 * 1.5 - 1548 - 2048 * 0.05) = 1421.0 @@ -143,15 +211,52 @@ class CapacityWeigherTestCase(test.TestCase): # weight = 0.0 # so, host4 should win: - weighed_host = self._get_weighed_host(hostinfo_list) + weight_properties = { + 'size': 1, + 'share_type': { + 'extra_specs': { + cap_thin_key: cap_thin, + } + } + } + weighed_host = self._get_weighed_host( + hostinfo_list, + weight_properties=weight_properties) self.assertEqual(0.0, weighed_host.weight) self.assertEqual( - 'host4', utils.extract_host(weighed_host.obj.host)) + winner, utils.extract_host(weighed_host.obj.host)) - def test_capacity_weight_multiplier_2(self): + @ddt.data( + {'cap_thin': ' True', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': ' False', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host1'}, + {'cap_thin': 'True', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': 'False', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host1'}, + {'cap_thin': 'true', + 'cap_thin_key': 'capabilities:thin_provisioning', + 'winner': 'host2'}, + {'cap_thin': 'false', + 'cap_thin_key': 'thin_provisioning', + 'winner': 'host1'}, + {'cap_thin': None, + 'cap_thin_key': None, + 'winner': 'host2'}, + ) + @ddt.unpack + def test_capacity_weight_multiplier_2(self, cap_thin, cap_thin_key, + winner): self.flags(capacity_weight_multiplier=2.0) hostinfo_list = self._get_all_hosts() + # Results for the 1st test + # {'capabilities:thin_provisioning': ' True'}: # host1: thin_provisioning = False # free_capacity_gb = 1024 # free = math.floor(1024-1024*0.1) = 921.0 @@ -163,18 +268,18 @@ class CapacityWeigherTestCase(test.TestCase): # free = math.floor(2048 * 2.0 - 1748 - 2048 * 0.1) = 2143.0 # free * 2 = 4286.0 # weight = 2.0 - # host3: thin_provisioning = False + # host3: thin_provisioning = [False] # free_capacity_gb = 512 # free = math.floor(256 - 512 * 0) = 256.0 # free * 2 = 512.0 # weight = 0.16 - # host4: thin_provisioning = True + # host4: thin_provisioning = [True] # max_over_subscription_ratio = 1.0 # free_capacity_gb = 200 # free = math.floor(2048 * 1.0 - 1848 - 2048 * 0.05) = 97.0 # free * 2 = 194.0 # weight = 0.0 - # host5: thin_provisioning = True + # host5: thin_provisioning = [True, False] # max_over_subscription_ratio = 1.5 # free_capacity_gb = 500 # free = math.floor(2048 * 1.5 - 1548 - 2048 * 0.05) = 1421.0 @@ -185,7 +290,17 @@ class CapacityWeigherTestCase(test.TestCase): # weight = 0.0 # so, host2 should win: - weighed_host = self._get_weighed_host(hostinfo_list) + weight_properties = { + 'size': 1, + 'share_type': { + 'extra_specs': { + cap_thin_key: cap_thin, + } + } + } + weighed_host = self._get_weighed_host( + hostinfo_list, + weight_properties=weight_properties) self.assertEqual(2.0, weighed_host.weight) self.assertEqual( - 'host2', utils.extract_host(weighed_host.obj.host)) + winner, utils.extract_host(weighed_host.obj.host)) diff --git a/releasenotes/notes/check-thin-provisioning-4bb702535f6b10b6.yaml b/releasenotes/notes/check-thin-provisioning-4bb702535f6b10b6.yaml new file mode 100644 index 0000000000..8108fe51d5 --- /dev/null +++ b/releasenotes/notes/check-thin-provisioning-4bb702535f6b10b6.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - Capacity filter and weigher scheduler logic was modified to + account for back ends that can support thin and thick provisioning + for shares. Over subscription calculation is triggered with the + presence of the ``thin_provisioning`` extra-spec in the share type + of the share being created.