Check 'thin_provisioning' in extra specs

Currently in the capacity filter and weigher of the scheduler,
we use the logic to evaluate whether there is enough capacity
to thin provision a share on a backend if the driver reports
thin_provisioning to be True. However, a driver may be able to
support both thin and thick provisioning. The logic does not
check whether the user wants the share to be provisioned as thin
or not.

In this patch, we check 'thin_provisioning' in extra specs of the
share type and decide whether to use the logic for thin or thick.
In the following two cases, we will use the thin logic:
1) 'thin_provisioning' is not set in extra specs. This is to
   provide backward compatibility.
2) 'thin_provisioning' is set in extra specs and it is
   '<is> True' or 'True'.

To provision a thick share on a backend that supports both
thin and thick, set one of the following in extra specs:
    {'thin_provisioning': 'False'}
    {'thin_provisioning': '<is> False'}
    {'capabilities:thin_provisioning': 'False'}
    {'capabilities:thin_provisioning': '<is> False'}

DocImpact
Change-Id: I238a7962425ea35c356c5ed2e31b8f68462b3769
Closes-Bug: #1578718
This commit is contained in:
xing-yang 2016-05-11 15:23:31 -04:00 committed by Goutham Pacha Ravi
parent 9abc9573de
commit 83c93c7767
8 changed files with 388 additions and 48 deletions

View File

@ -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})

View File

@ -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
# '<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 '<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

View File

@ -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(

View File

@ -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,

View File

@ -121,31 +121,76 @@ class HostFiltersTestCase(test.TestCase):
@ddt.data(
{'size': 100, 'cap_thin': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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': '<is> 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,

View File

@ -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': '<is> True'}},
True),
({'extra_specs': {'thin_provisioning': '<is> False'}},
False),
({'extra_specs': {'thin_provisioning': '<not> 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)

View File

@ -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': '<is> True',
'cap_thin_key': 'capabilities:thin_provisioning',
'winner': 'host2'},
{'cap_thin': '<is> 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': '<is> 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': '<is> True',
'cap_thin_key': 'capabilities:thin_provisioning',
'winner': 'host4'},
{'cap_thin': '<is> 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': '<is> 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': '<is> True',
'cap_thin_key': 'capabilities:thin_provisioning',
'winner': 'host2'},
{'cap_thin': '<is> 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': '<is> 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))

View File

@ -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.