Coverage for manila/tests/scheduler/weighers/test_capacity.py: 100%
58 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright 2011-2012 OpenStack LLC.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15"""
16Tests For Capacity Weigher.
17"""
19from unittest import mock
21import ddt
22from oslo_config import cfg
24from manila import context
25from manila.scheduler.weighers import base_host
26from manila.scheduler.weighers import capacity
27from manila.share import utils
28from manila import test
29from manila.tests.scheduler import fakes
31CONF = cfg.CONF
34@ddt.ddt
35class CapacityWeigherTestCase(test.TestCase):
36 def setUp(self):
37 super(CapacityWeigherTestCase, self).setUp()
38 self.host_manager = fakes.FakeHostManager()
39 self.weight_handler = base_host.HostWeightHandler(
40 'manila.scheduler.weighers')
42 def _get_weighed_host(self, hosts, weight_properties=None, index=0):
43 if weight_properties is None:
44 weight_properties = {'size': 1}
45 return self.weight_handler.get_weighed_objects(
46 [capacity.CapacityWeigher],
47 hosts,
48 weight_properties)[index]
50 @mock.patch('manila.db.api.IMPL.service_get_all_by_topic')
51 def _get_all_hosts(self, _mock_service_get_all_by_topic, disabled=False):
52 ctxt = context.get_admin_context()
53 fakes.mock_host_manager_db_calls(_mock_service_get_all_by_topic,
54 disabled=disabled)
55 host_states = self.host_manager.get_all_host_states_share(ctxt)
56 _mock_service_get_all_by_topic.assert_called_once_with(
57 ctxt, CONF.share_topic, consider_disabled=False)
58 return host_states
60 # NOTE(xyang): If thin_provisioning = True and
61 # max_over_subscription_ratio >= 1, use the following formula:
62 # free = math.floor(total * host_state.max_over_subscription_ratio
63 # - host_state.provisioned_capacity_gb
64 # - total * reserved)
65 # Otherwise, use the following formula:
66 # free = math.floor(free_space - total * reserved)
68 @ddt.data(
69 {'cap_thin': '<is> True',
70 'cap_thin_key': 'capabilities:thin_provisioning',
71 'winner': 'host2'},
72 {'cap_thin': '<is> False',
73 'cap_thin_key': 'thin_provisioning',
74 'winner': 'host1'},
75 {'cap_thin': 'True',
76 'cap_thin_key': 'capabilities:thin_provisioning',
77 'winner': 'host2'},
78 {'cap_thin': 'False',
79 'cap_thin_key': 'thin_provisioning',
80 'winner': 'host1'},
81 {'cap_thin': 'true',
82 'cap_thin_key': 'capabilities:thin_provisioning',
83 'winner': 'host2'},
84 {'cap_thin': 'false',
85 'cap_thin_key': 'thin_provisioning',
86 'winner': 'host1'},
87 {'cap_thin': None,
88 'cap_thin_key': None,
89 'winner': 'host2'},
90 )
91 @ddt.unpack
92 def test_default_of_spreading_first(self, cap_thin, cap_thin_key,
93 winner):
94 hosts = self._get_all_hosts() # pylint: disable=no-value-for-parameter
96 # Results for the 1st test
97 # {'capabilities:thin_provisioning': '<is> True'}:
98 # host1: thin_provisioning = False
99 # free_capacity_gb = 1024
100 # free = math.floor(1024 - 1024 * 0.1) = 921.0
101 # weight = 0.40
102 # host2: thin_provisioning = True
103 # max_over_subscription_ratio = 2.0
104 # free_capacity_gb = 300
105 # free = math.floor(2048 * 2.0 - 1748 - 2048 * 0.1)=2143.0
106 # weight = 1.0
107 # host3: thin_provisioning = [False]
108 # free_capacity_gb = 512
109 # free = math.floor(256 - 512 * 0)=256.0
110 # weight = 0.08
111 # host4: thin_provisioning = [True]
112 # max_over_subscription_ratio = 1.0
113 # free_capacity_gb = 200
114 # free = math.floor(2048 * 1.0 - 1848 - 2048 * 0.05) = 97.0
115 # weight = 0.0
116 # host5: thin_provisioning = [True, False]
117 # max_over_subscription_ratio = 1.5
118 # free_capacity_gb = 500
119 # free = math.floor(2048 * 1.5 - 1548 - 2048 * 0.05) = 1421.0
120 # weight = 0.65
121 # host6: thin_provisioning = False
122 # free = inf
123 # weight = 0.0
125 # so, host2 should win:
126 weight_properties = {
127 'size': 1,
128 'share_type': {
129 'extra_specs': {
130 cap_thin_key: cap_thin,
131 }
132 }
133 }
134 weighed_host = self._get_weighed_host(
135 hosts,
136 weight_properties=weight_properties)
137 self.assertEqual(1.0, weighed_host.weight)
138 self.assertEqual(
139 winner, utils.extract_host(weighed_host.obj.host))
141 def test_unknown_is_last(self):
142 hosts = self._get_all_hosts() # pylint: disable=no-value-for-parameter
144 last_host = self._get_weighed_host(hosts, index=-1)
145 self.assertEqual(
146 'host6', utils.extract_host(last_host.obj.host))
147 self.assertEqual(0.0, last_host.weight)
149 @ddt.data(
150 {'cap_thin': '<is> True',
151 'cap_thin_key': 'capabilities:thin_provisioning',
152 'winner': 'host4'},
153 {'cap_thin': '<is> False',
154 'cap_thin_key': 'thin_provisioning',
155 'winner': 'host2'},
156 {'cap_thin': 'True',
157 'cap_thin_key': 'capabilities:thin_provisioning',
158 'winner': 'host4'},
159 {'cap_thin': 'False',
160 'cap_thin_key': 'thin_provisioning',
161 'winner': 'host2'},
162 {'cap_thin': 'true',
163 'cap_thin_key': 'capabilities:thin_provisioning',
164 'winner': 'host4'},
165 {'cap_thin': 'false',
166 'cap_thin_key': 'thin_provisioning',
167 'winner': 'host2'},
168 {'cap_thin': None,
169 'cap_thin_key': None,
170 'winner': 'host4'},
171 )
172 @ddt.unpack
173 def test_capacity_weight_multiplier_negative_1(self, cap_thin,
174 cap_thin_key,
175 winner):
176 self.flags(capacity_weight_multiplier=-1.0)
177 hosts = self._get_all_hosts() # pylint: disable=no-value-for-parameter
179 # Results for the 1st test
180 # {'capabilities:thin_provisioning': '<is> True'}:
181 # host1: thin_provisioning = False
182 # free_capacity_gb = 1024
183 # free = math.floor(1024 - 1024 * 0.1) = 921.0
184 # free * (-1) = -921.0
185 # weight = -0.40
186 # host2: thin_provisioning = True
187 # max_over_subscription_ratio = 2.0
188 # free_capacity_gb = 300
189 # free = math.floor(2048 * 2.0-1748-2048 * 0.1) = 2143.0
190 # free * (-1) = -2143.0
191 # weight = -1.0
192 # host3: thin_provisioning = [False]
193 # free_capacity_gb = 512
194 # free = math.floor(256 - 512 * 0) = 256.0
195 # free * (-1) = -256.0
196 # weight = -0.08
197 # host4: thin_provisioning = [True]
198 # max_over_subscription_ratio = 1.0
199 # free_capacity_gb = 200
200 # free = math.floor(2048 * 1.0 - 1848 - 2048 * 0.05) = 97.0
201 # free * (-1) = -97.0
202 # weight = 0.0
203 # host5: thin_provisioning = [True, False]
204 # max_over_subscription_ratio = 1.5
205 # free_capacity_gb = 500
206 # free = math.floor(2048 * 1.5 - 1548 - 2048 * 0.05) = 1421.0
207 # free * (-1) = -1421.0
208 # weight = -0.65
209 # host6: thin_provisioning = False
210 # free = inf
211 # free * (-1) = -inf
212 # weight = 0.0
214 # so, host4 should win:
215 weight_properties = {
216 'size': 1,
217 'share_type': {
218 'extra_specs': {
219 cap_thin_key: cap_thin,
220 }
221 }
222 }
223 weighed_host = self._get_weighed_host(
224 hosts,
225 weight_properties=weight_properties)
226 self.assertEqual(0.0, weighed_host.weight)
227 self.assertEqual(
228 winner, utils.extract_host(weighed_host.obj.host))
230 @ddt.data(
231 {'cap_thin': '<is> True',
232 'cap_thin_key': 'capabilities:thin_provisioning',
233 'winner': 'host2'},
234 {'cap_thin': '<is> False',
235 'cap_thin_key': 'thin_provisioning',
236 'winner': 'host1'},
237 {'cap_thin': 'True',
238 'cap_thin_key': 'capabilities:thin_provisioning',
239 'winner': 'host2'},
240 {'cap_thin': 'False',
241 'cap_thin_key': 'thin_provisioning',
242 'winner': 'host1'},
243 {'cap_thin': 'true',
244 'cap_thin_key': 'capabilities:thin_provisioning',
245 'winner': 'host2'},
246 {'cap_thin': 'false',
247 'cap_thin_key': 'thin_provisioning',
248 'winner': 'host1'},
249 {'cap_thin': None,
250 'cap_thin_key': None,
251 'winner': 'host2'},
252 )
253 @ddt.unpack
254 def test_capacity_weight_multiplier_2(self, cap_thin, cap_thin_key,
255 winner):
256 self.flags(capacity_weight_multiplier=2.0)
257 hosts = self._get_all_hosts() # pylint: disable=no-value-for-parameter
259 # Results for the 1st test
260 # {'capabilities:thin_provisioning': '<is> True'}:
261 # host1: thin_provisioning = False
262 # free_capacity_gb = 1024
263 # free = math.floor(1024-1024*0.1) = 921.0
264 # free * 2 = 1842.0
265 # weight = 0.81
266 # host2: thin_provisioning = True
267 # max_over_subscription_ratio = 2.0
268 # free_capacity_gb = 300
269 # free = math.floor(2048 * 2.0 - 1748 - 2048 * 0.1) = 2143.0
270 # free * 2 = 4286.0
271 # weight = 2.0
272 # host3: thin_provisioning = [False]
273 # free_capacity_gb = 512
274 # free = math.floor(256 - 512 * 0) = 256.0
275 # free * 2 = 512.0
276 # weight = 0.16
277 # host4: thin_provisioning = [True]
278 # max_over_subscription_ratio = 1.0
279 # free_capacity_gb = 200
280 # free = math.floor(2048 * 1.0 - 1848 - 2048 * 0.05) = 97.0
281 # free * 2 = 194.0
282 # weight = 0.0
283 # host5: thin_provisioning = [True, False]
284 # max_over_subscription_ratio = 1.5
285 # free_capacity_gb = 500
286 # free = math.floor(2048 * 1.5 - 1548 - 2048 * 0.05) = 1421.0
287 # free * 2 = 2842.0
288 # weight = 1.29
289 # host6: thin_provisioning = False
290 # free = inf
291 # weight = 0.0
293 # so, host2 should win:
294 weight_properties = {
295 'size': 1,
296 'share_type': {
297 'extra_specs': {
298 cap_thin_key: cap_thin,
299 }
300 }
301 }
302 weighed_host = self._get_weighed_host(
303 hosts, weight_properties=weight_properties)
304 self.assertEqual(2.0, weighed_host.weight)
305 self.assertEqual(
306 winner, utils.extract_host(weighed_host.obj.host))