Coverage for manila/tests/share/drivers/container/test_storage_helper.py: 99%

151 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright 2016 Mirantis, Inc. 

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"""Unit tests for the Storage helper module.""" 

16 

17import functools 

18from unittest import mock 

19 

20import ddt 

21 

22from manila import exception 

23from manila.share import configuration 

24from manila.share.drivers.container import storage_helper 

25from manila import test 

26from manila.tests import fake_share as base_fake_share 

27from manila.tests.share.drivers.container.fakes import fake_share 

28 

29 

30@ddt.ddt 

31class LVMHelperTestCase(test.TestCase): 

32 """Tests ContainerShareDriver""" 

33 

34 def setUp(self): 

35 super(LVMHelperTestCase, self).setUp() 

36 self.share = fake_share() 

37 self.fake_conf = configuration.Configuration(None) 

38 self.fake_conf.container_volume_mount_path = "/tmp/shares" 

39 self.LVMHelper = storage_helper.LVMHelper(configuration=self.fake_conf) 

40 self.context = mock.Mock() 

41 

42 def fake_exec_sync(self, *args, **kwargs): 

43 kwargs['execute_arguments'].append(args) 

44 try: 

45 ret_val = kwargs['ret_val'] 

46 except KeyError: 

47 ret_val = None 

48 return ret_val 

49 

50 def test_lvmhelper_setup_explodes_in_gore_on_no_config_supplied(self): 

51 self.assertRaises(exception.ManilaException, 

52 storage_helper.LVMHelper, 

53 None) 

54 

55 @ddt.data("62.50g 72.50g", " 72.50g 62.50g\n", " <62.50g <72.50g\n") 

56 def test_get_share_server_pools(self, ret_vgs): 

57 expected_result = [{'reserved_percentage': 0, 

58 'reserved_snapshot_percentage': 0, 

59 'reserved_share_extend_percentage': 0, 

60 'pool_name': 'manila_docker_volumes', 

61 'total_capacity_gb': 72.5, 

62 'free_capacity_gb': 62.5}] 

63 self.mock_object(self.LVMHelper, "_execute", 

64 mock.Mock(return_value=(ret_vgs, 0))) 

65 

66 result = self.LVMHelper.get_share_server_pools() 

67 

68 self.assertEqual(expected_result, result) 

69 

70 def test__get_lv_device(self): 

71 fake_share_name = 'fakeshareid' 

72 self.assertEqual("/dev/manila_docker_volumes/%s" % fake_share_name, 

73 self.LVMHelper._get_lv_device(fake_share_name)) 

74 

75 def test__get_lv_folder(self): 

76 fake_share_name = 'fakeshareid' 

77 self.assertEqual("/tmp/shares/%s" % fake_share_name, 

78 self.LVMHelper._get_lv_folder(fake_share_name)) 

79 

80 def test_provide_storage(self): 

81 actual_arguments = [] 

82 fake_share_name = 'fakeshareid' 

83 expected_arguments = [ 

84 ('lvcreate', '-p', 'rw', '-L', '1G', '-n', 'fakeshareid', 

85 'manila_docker_volumes'), 

86 ('mkfs.ext4', '/dev/manila_docker_volumes/fakeshareid'), 

87 ] 

88 self.LVMHelper._execute = functools.partial( 

89 self.fake_exec_sync, execute_arguments=actual_arguments, 

90 ret_val='') 

91 

92 self.LVMHelper.provide_storage(fake_share_name, 1) 

93 

94 self.assertEqual(expected_arguments, actual_arguments) 

95 

96 @ddt.data(None, exception.ProcessExecutionError) 

97 def test__try_to_unmount_device(self, side_effect): 

98 device = {} 

99 mock_warning = self.mock_object(storage_helper.LOG, 'warning') 

100 mock_execute = self.mock_object(self.LVMHelper, '_execute', 

101 mock.Mock(side_effect=side_effect)) 

102 self.LVMHelper._try_to_unmount_device(device) 

103 

104 mock_execute.assert_called_once_with( 

105 "umount", device, run_as_root=True 

106 ) 

107 if side_effect is not None: 

108 mock_warning.assert_called_once() 

109 

110 def test_remove_storage(self): 

111 fake_share_name = 'fakeshareid' 

112 fake_device = {} 

113 

114 mock_get_lv_device = self.mock_object( 

115 self.LVMHelper, '_get_lv_device', 

116 mock.Mock(return_value=fake_device)) 

117 mock_try_to_umount = self.mock_object(self.LVMHelper, 

118 '_try_to_unmount_device') 

119 mock_execute = self.mock_object(self.LVMHelper, '_execute') 

120 

121 self.LVMHelper.remove_storage(fake_share_name) 

122 

123 mock_get_lv_device.assert_called_once_with( 

124 fake_share_name 

125 ) 

126 mock_try_to_umount.assert_called_once_with(fake_device) 

127 mock_execute.assert_called_once_with( 

128 'lvremove', '-f', '--autobackup', 'n', fake_device, 

129 run_as_root=True 

130 ) 

131 

132 def test_remove_storage_lvremove_failed(self): 

133 fake_share_name = 'fakeshareid' 

134 

135 def fake_execute(*args, **kwargs): 

136 if 'lvremove' in args: 

137 raise exception.ProcessExecutionError() 

138 

139 self.mock_object(storage_helper.LOG, "warning") 

140 self.mock_object(self.LVMHelper, "_execute", fake_execute) 

141 

142 self.LVMHelper.remove_storage(fake_share_name) 

143 

144 self.assertTrue(storage_helper.LOG.warning.called) 

145 

146 @ddt.data(None, exception.ProcessExecutionError) 

147 def test_rename_storage(self, side_effect): 

148 fake_old_share_name = 'fake_old_name' 

149 fake_new_share_name = 'fake_new_name' 

150 fake_new_device = "/dev/new_device" 

151 fake_old_device = "/dev/old_device" 

152 

153 mock_get_lv_device = self.mock_object( 

154 self.LVMHelper, '_get_lv_device', 

155 mock.Mock(side_effect=[fake_old_device, fake_new_device])) 

156 mock_try_to_umount = self.mock_object(self.LVMHelper, 

157 '_try_to_unmount_device') 

158 

159 mock_execute = self.mock_object(self.LVMHelper, '_execute', 

160 mock.Mock(side_effect=side_effect)) 

161 

162 if side_effect is None: 

163 self.LVMHelper.rename_storage(fake_old_share_name, 

164 fake_new_share_name) 

165 else: 

166 self.assertRaises(exception.ProcessExecutionError, 

167 self.LVMHelper.rename_storage, 

168 fake_old_share_name, fake_new_share_name) 

169 mock_try_to_umount.assert_called_once_with(fake_old_device) 

170 mock_execute.assert_called_once_with( 

171 "lvrename", "--autobackup", "n", fake_old_device, fake_new_device, 

172 run_as_root=True 

173 ) 

174 mock_get_lv_device.assert_has_calls([ 

175 mock.call(fake_old_share_name), 

176 mock.call(fake_new_share_name) 

177 ]) 

178 

179 def test_extend_share(self): 

180 actual_arguments = [] 

181 expected_arguments = [ 

182 ('lvextend', '-L', 'shareG', '-n', 

183 '/dev/manila_docker_volumes/fakeshareid'), 

184 ('e2fsck', '-f', '-y', '/dev/manila_docker_volumes/fakeshareid'), 

185 ('resize2fs', '/dev/manila_docker_volumes/fakeshareid'), 

186 ] 

187 fake_share_name = 'fakeshareid' 

188 self.LVMHelper._execute = functools.partial( 

189 self.fake_exec_sync, execute_arguments=actual_arguments, 

190 ret_val='') 

191 

192 self.LVMHelper.extend_share(fake_share_name, 'share', 3) 

193 

194 self.assertEqual(expected_arguments, actual_arguments) 

195 

196 def test_get_size(self): 

197 share_name = 'fakeshareid' 

198 fake_old_device = {} 

199 

200 mock_get_lv_device = self.mock_object( 

201 self.LVMHelper, '_get_lv_device', 

202 mock.Mock(return_value=fake_old_device)) 

203 mock_execute = self.mock_object(self.LVMHelper, '_execute', 

204 mock.Mock(return_value=[1, "args"])) 

205 

206 result = self.LVMHelper.get_size(share_name) 

207 

208 mock_execute.assert_called_once_with( 

209 "lvs", "-o", "lv_size", "--noheadings", "--nosuffix", "--units", 

210 "g", fake_old_device, run_as_root=True 

211 ) 

212 mock_get_lv_device.assert_called_once_with(share_name) 

213 self.assertEqual(result, 1) 

214 

215 @ddt.data({'source_host': 'host@back1#vg1', 'dest_host': 'host@back2#vg2', 

216 'compatible': False}, 

217 {'source_host': 'host@back1#vg1', 'dest_host': 'host@back2#vg1', 

218 'compatible': True}, 

219 {'source_host': 'host@back1#vg1', 'dest_host': 'host@back1#vg1', 

220 'compatible': True}) 

221 @ddt.unpack 

222 def test_migration_check_compatibility( 

223 self, source_host, dest_host, compatible): 

224 mock_exception_log = self.mock_object(storage_helper.LOG, 'exception') 

225 

226 source_share = base_fake_share.fake_share_instance(host=source_host) 

227 dest_share = base_fake_share.fake_share_instance(host=dest_host) 

228 

229 migration_compatibility = self.LVMHelper.migration_check_compatibility( 

230 self.context, source_share, dest_share, share_server=None, 

231 destination_share_server=None) 

232 

233 expected_compatibility = { 

234 'compatible': compatible, 

235 'writable': True, 

236 'nondisruptive': False, 

237 'preserve_metadata': True, 

238 'preserve_snapshots': False, 

239 } 

240 self.assertDictEqual(expected_compatibility, migration_compatibility) 

241 if not compatible: 

242 mock_exception_log.assert_called_once() 

243 

244 def test_migration_continue(self): 

245 end1Phase = self.LVMHelper.migration_continue( 

246 self.context, None, None, None, None, share_server=None, 

247 destination_share_server=None) 

248 self.assertTrue(end1Phase) 

249 

250 def test_migration_get_progress(self): 

251 progress = self.LVMHelper.migration_get_progress( 

252 self.context, None, None, None, None, share_server=None, 

253 destination_share_server=None) 

254 expected_progress = { 

255 'total_progress': 100, 

256 } 

257 self.assertDictEqual(expected_progress, progress) 

258 

259 @ddt.data({'source_host': 'host@back1', 'dest_host': 'host@back1', 

260 'shares_specs': {}}, 

261 {'source_host': 'host@back1', 'dest_host': 'host@back2#vg1', 

262 'shares_specs': {'shares_req_spec': [ 

263 {'share_instance_properties': {'host': 'host@back1#vg2'}} 

264 ]}}) 

265 @ddt.unpack 

266 def test_share_server_migration_check_compatibility_false( 

267 self, source_host, dest_host, shares_specs): 

268 not_compatible = { 

269 'compatible': False, 

270 'writable': None, 

271 'nondisruptive': None, 

272 'preserve_snapshots': None, 

273 'migration_cancel': None, 

274 'migration_get_progress': None, 

275 } 

276 mock_error_log = self.mock_object(storage_helper.LOG, 'error') 

277 

278 source_server = {'id': 'fake_id', 'host': source_host} 

279 migration_compatibility = ( 

280 self.LVMHelper.share_server_migration_check_compatibility( 

281 self.context, source_server, dest_host, None, None, 

282 shares_specs)) 

283 

284 self.assertDictEqual(not_compatible, migration_compatibility) 

285 mock_error_log.assert_called_once() 

286 

287 @ddt.data({'source_host': 'host@back1', 'dest_host': 'host@back2#vg1', 

288 'shares_specs': {'shares_req_spec': [ 

289 {'share_instance_properties': {'host': 'host@back1#vg1'}} 

290 ]}}, 

291 {'source_host': 'host@back1', 'dest_host': 'host@back2', 

292 'shares_specs': {'shares_req_spec': [ 

293 {'share_instance_properties': {'host': 'host@back1#vg1'}} 

294 ]}}) 

295 @ddt.unpack 

296 def test_share_server_migration_check_compatibility_true( 

297 self, source_host, dest_host, shares_specs): 

298 compatible = { 

299 'compatible': True, 

300 'writable': True, 

301 'nondisruptive': False, 

302 'preserve_snapshots': False, 

303 'migration_cancel': True, 

304 'migration_get_progress': True, 

305 } 

306 

307 source_server = {'id': 'fake_id', 'host': source_host} 

308 migration_compatibility = ( 

309 self.LVMHelper.share_server_migration_check_compatibility( 

310 self.context, source_server, dest_host, None, None, 

311 shares_specs)) 

312 

313 self.assertDictEqual(compatible, migration_compatibility) 

314 

315 def test_share_server_migration_continue(self): 

316 end1Phase = self.LVMHelper.share_server_migration_continue( 

317 self.context, None, None, None, None) 

318 self.assertTrue(end1Phase) 

319 

320 def test_share_server_migration_get_progess(self): 

321 progress = self.LVMHelper.share_server_migration_get_progress( 

322 self.context, None, None, None, None) 

323 expected_progress = { 

324 'total_progress': 100, 

325 } 

326 self.assertDictEqual(expected_progress, progress) 

327 

328 def test_get_share_pool_name(self): 

329 fake_vg_name = 'fake_vg' 

330 self.LVMHelper.configuration.container_volume_group = fake_vg_name 

331 

332 vg_name = self.LVMHelper.get_share_pool_name('fake_share_id') 

333 self.assertEqual(vg_name, fake_vg_name)