Merge "Check 'thin_provisioning' in extra specs"
This commit is contained in:
commit
eddeff89bd
@ -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})
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
64
manila/tests/scheduler/test_utils.py
Normal file
64
manila/tests/scheduler/test_utils.py
Normal 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)
|
@ -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))
|
||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user