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

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""" 

18 

19from unittest import mock 

20 

21import ddt 

22from oslo_config import cfg 

23 

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 

30 

31CONF = cfg.CONF 

32 

33 

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') 

41 

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] 

49 

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 

59 

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) 

67 

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 

95 

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 

124 

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

140 

141 def test_unknown_is_last(self): 

142 hosts = self._get_all_hosts() # pylint: disable=no-value-for-parameter 

143 

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) 

148 

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 

178 

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 

213 

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

229 

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 

258 

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 

292 

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