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:
parent
9abc9573de
commit
83c93c7767
@ -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