Coverage for manila/tests/share/test_migration.py: 100%

143 statements  

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

1# Copyright 2015 Hitachi Data Systems 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 

16import time 

17from unittest import mock 

18 

19import ddt 

20 

21from manila.common import constants 

22from manila import context 

23from manila import db 

24from manila import exception 

25from manila.share import access as access_helper 

26from manila.share import api as share_api 

27from manila.share import migration 

28from manila.share import rpcapi as share_rpcapi 

29from manila import test 

30from manila.tests import db_utils 

31from manila import utils 

32 

33 

34@ddt.ddt 

35class ShareMigrationHelperTestCase(test.TestCase): 

36 """Tests ShareMigrationHelper.""" 

37 

38 def setUp(self): 

39 super(ShareMigrationHelperTestCase, self).setUp() 

40 self.share = db_utils.create_share() 

41 self.share_instance = db_utils.create_share_instance( 

42 share_id=self.share['id'], 

43 share_network_id='fake_network_id') 

44 self.access_helper = access_helper.ShareInstanceAccess(db, None) 

45 self.context = context.get_admin_context() 

46 self.helper = migration.ShareMigrationHelper( 

47 self.context, db, self.access_helper) 

48 

49 def test_delete_instance_and_wait(self): 

50 

51 # mocks 

52 self.mock_object(share_api.API, 'delete_instance') 

53 self.mock_object(db, 'share_instance_get', 

54 mock.Mock(side_effect=[self.share_instance, 

55 exception.NotFound()])) 

56 self.mock_object(time, 'sleep') 

57 

58 # run 

59 self.helper.delete_instance_and_wait(self.share_instance) 

60 

61 # asserts 

62 share_api.API.delete_instance.assert_called_once_with( 

63 self.context, self.share_instance, True) 

64 

65 db.share_instance_get.assert_has_calls([ 

66 mock.call(self.context, self.share_instance['id']), 

67 mock.call(self.context, self.share_instance['id'])]) 

68 

69 time.sleep.assert_called_once_with(1.414) 

70 

71 def test_delete_instance_and_wait_timeout(self): 

72 

73 # mocks 

74 self.mock_object(share_api.API, 'delete_instance') 

75 

76 self.mock_object(db, 'share_instance_get', 

77 mock.Mock(side_effect=[self.share_instance, None])) 

78 self.mock_object(time, 'sleep') 

79 

80 now = time.time() 

81 timeout = now + 310 

82 

83 self.mock_object(time, 'time', 

84 mock.Mock(side_effect=[now, timeout])) 

85 

86 # run 

87 self.assertRaises(exception.ShareMigrationFailed, 

88 self.helper.delete_instance_and_wait, 

89 self.share_instance) 

90 

91 # asserts 

92 share_api.API.delete_instance.assert_called_once_with( 

93 self.context, self.share_instance, True) 

94 

95 db.share_instance_get.assert_called_once_with( 

96 self.context, self.share_instance['id']) 

97 

98 time.time.assert_has_calls([mock.call(), mock.call()]) 

99 

100 def test_delete_instance_and_wait_not_found(self): 

101 

102 # mocks 

103 self.mock_object(share_api.API, 'delete_instance') 

104 self.mock_object(db, 'share_instance_get', 

105 mock.Mock(side_effect=exception.NotFound)) 

106 

107 # run 

108 self.helper.delete_instance_and_wait(self.share_instance) 

109 

110 # asserts 

111 share_api.API.delete_instance.assert_called_once_with( 

112 self.context, self.share_instance, True) 

113 

114 db.share_instance_get.assert_called_once_with( 

115 self.context, self.share_instance['id']) 

116 

117 def test_create_instance_and_wait(self): 

118 

119 host = 'fake_host' 

120 

121 share_instance_creating = db_utils.create_share_instance( 

122 share_id=self.share['id'], status=constants.STATUS_CREATING, 

123 share_network_id='fake_network_id') 

124 share_instance_available = db_utils.create_share_instance( 

125 share_id=self.share['id'], status=constants.STATUS_AVAILABLE, 

126 share_network_id='fake_network_id') 

127 

128 # mocks 

129 self.mock_object(share_api.API, 'create_instance', 

130 mock.Mock(return_value=share_instance_creating)) 

131 self.mock_object(db, 'share_instance_get', 

132 mock.Mock(side_effect=[share_instance_creating, 

133 share_instance_available])) 

134 self.mock_object(time, 'sleep') 

135 

136 # run 

137 self.helper.create_instance_and_wait( 

138 self.share, host, 'fake_net_id', 'fake_az_id', 'fake_type_id') 

139 

140 # asserts 

141 share_api.API.create_instance.assert_called_once_with( 

142 self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id', 

143 share_type_id='fake_type_id') 

144 

145 db.share_instance_get.assert_has_calls([ 

146 mock.call(self.context, share_instance_creating['id'], 

147 with_share_data=True), 

148 mock.call(self.context, share_instance_creating['id'], 

149 with_share_data=True)]) 

150 

151 time.sleep.assert_called_once_with(1.414) 

152 

153 def test_create_instance_and_wait_status_error(self): 

154 

155 host = 'fake_host' 

156 

157 share_instance_error = db_utils.create_share_instance( 

158 share_id=self.share['id'], status=constants.STATUS_ERROR, 

159 share_network_id='fake_network_id') 

160 

161 # mocks 

162 self.mock_object(share_api.API, 'create_instance', 

163 mock.Mock(return_value=share_instance_error)) 

164 self.mock_object(self.helper, 'cleanup_new_instance') 

165 self.mock_object(db, 'share_instance_get', 

166 mock.Mock(return_value=share_instance_error)) 

167 

168 # run 

169 self.assertRaises( 

170 exception.ShareMigrationFailed, 

171 self.helper.create_instance_and_wait, self.share, 

172 host, 'fake_net_id', 'fake_az_id', 'fake_type_id') 

173 

174 # asserts 

175 share_api.API.create_instance.assert_called_once_with( 

176 self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id', 

177 share_type_id='fake_type_id') 

178 

179 db.share_instance_get.assert_called_once_with( 

180 self.context, share_instance_error['id'], with_share_data=True) 

181 

182 self.helper.cleanup_new_instance.assert_called_once_with( 

183 share_instance_error) 

184 

185 def test_create_instance_and_wait_timeout(self): 

186 

187 host = 'fake_host' 

188 

189 share_instance_creating = db_utils.create_share_instance( 

190 share_id=self.share['id'], status=constants.STATUS_CREATING, 

191 share_network_id='fake_network_id') 

192 

193 # mocks 

194 self.mock_object(share_api.API, 'create_instance', 

195 mock.Mock(return_value=share_instance_creating)) 

196 

197 self.mock_object(self.helper, 'cleanup_new_instance') 

198 

199 self.mock_object(db, 'share_instance_get', 

200 mock.Mock(return_value=share_instance_creating)) 

201 self.mock_object(time, 'sleep') 

202 

203 now = time.time() 

204 timeout = now + 310 

205 

206 self.mock_object(time, 'time', mock.Mock(side_effect=[now, timeout])) 

207 

208 # run 

209 self.assertRaises( 

210 exception.ShareMigrationFailed, 

211 self.helper.create_instance_and_wait, self.share, 

212 host, 'fake_net_id', 'fake_az_id', 'fake_type_id') 

213 

214 # asserts 

215 share_api.API.create_instance.assert_called_once_with( 

216 self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id', 

217 share_type_id='fake_type_id') 

218 

219 db.share_instance_get.assert_called_once_with( 

220 self.context, share_instance_creating['id'], with_share_data=True) 

221 

222 time.time.assert_has_calls([mock.call(), mock.call()]) 

223 

224 self.helper.cleanup_new_instance.assert_called_once_with( 

225 share_instance_creating) 

226 

227 @ddt.data(constants.STATUS_ACTIVE, constants.STATUS_ERROR, 

228 constants.STATUS_CREATING) 

229 def test_wait_for_share_server(self, status): 

230 

231 server = db_utils.create_share_server(status=status) 

232 

233 # mocks 

234 self.mock_object(db, 'share_server_get', 

235 mock.Mock(return_value=server)) 

236 

237 # run 

238 if status == constants.STATUS_ACTIVE: 

239 result = self.helper.wait_for_share_server('fake_server_id') 

240 self.assertEqual(server, result) 

241 elif status == constants.STATUS_ERROR: 

242 self.assertRaises( 

243 exception.ShareServerNotCreated, 

244 self.helper.wait_for_share_server, 'fake_server_id') 

245 else: 

246 self.mock_object(time, 'sleep') 

247 self.assertRaises( 

248 exception.ShareServerNotReady, 

249 self.helper.wait_for_share_server, 'fake_server_id') 

250 

251 # asserts 

252 db.share_server_get.assert_called_with(self.context, 'fake_server_id') 

253 

254 @ddt.data(None, 'fakehost@fakebackend') 

255 def test_revert_access_rules(self, dest_host): 

256 

257 share_instance = db_utils.create_share_instance( 

258 share_id=self.share['id'], status=constants.STATUS_AVAILABLE) 

259 share_instance_ids = [instance['id'] for instance in [share_instance]] 

260 

261 access = db_utils.create_access(share_id=self.share['id'], 

262 access_to='fake_ip', 

263 access_level='rw') 

264 

265 server = db_utils.create_share_server(share_id=self.share['id']) 

266 

267 # mocks 

268 self.mock_object(self.access_helper, 'update_access_rules') 

269 get_and_update_call = self.mock_object( 

270 self.access_helper, 'get_and_update_share_instance_access_rules', 

271 mock.Mock(return_value=[access])) 

272 mock_update_access_for_instances = self.mock_object( 

273 share_rpcapi.ShareAPI, 'update_access_for_instances') 

274 

275 # run 

276 self.helper.revert_access_rules([share_instance], server, 

277 dest_host=dest_host) 

278 

279 # asserts 

280 get_and_update_call.assert_called_once_with( 

281 self.context, share_instance_id=share_instance['id'], 

282 updates={'state': constants.ACCESS_STATE_QUEUED_TO_APPLY}) 

283 if dest_host: 

284 mock_update_access_for_instances.assert_called_once_with( 

285 self.context, dest_host, share_instance_ids, server) 

286 else: 

287 self.access_helper.update_access_rules.assert_called_once_with( 

288 self.context, share_instance['id'], share_server=server) 

289 

290 @ddt.data(True, False) 

291 def test_apply_new_access_rules_there_are_rules(self, prior_rules): 

292 

293 new_share_instance = db_utils.create_share_instance( 

294 share_id=self.share['id'], status=constants.STATUS_AVAILABLE, 

295 access_rules_status='active') 

296 rules = None 

297 if prior_rules: 

298 rules = [ 

299 db_utils.create_access( 

300 share_id=self.share['id'], access_to='fake_ip') 

301 ] 

302 

303 # mocks 

304 self.mock_object(db, 'share_instance_access_copy', mock.Mock( 

305 return_value=rules)) 

306 self.mock_object(share_api.API, 'allow_access_to_instance') 

307 self.mock_object(utils, 'wait_for_access_update') 

308 

309 # run 

310 self.helper.apply_new_access_rules(new_share_instance, 

311 self.share['id']) 

312 

313 # asserts 

314 db.share_instance_access_copy.assert_called_once_with( 

315 self.context, self.share['id'], new_share_instance['id']) 

316 if prior_rules: 

317 share_api.API.allow_access_to_instance.assert_called_with( 

318 self.context, new_share_instance) 

319 utils.wait_for_access_update.assert_called_with( 

320 self.context, db, new_share_instance, 

321 self.helper.migration_wait_access_rules_timeout) 

322 else: 

323 self.assertFalse(share_api.API.allow_access_to_instance.called) 

324 self.assertFalse(utils.wait_for_access_update.called) 

325 

326 @ddt.data(None, Exception('fake')) 

327 def test_cleanup_new_instance(self, exc): 

328 

329 # mocks 

330 self.mock_object(self.helper, 'delete_instance_and_wait', 

331 mock.Mock(side_effect=exc)) 

332 

333 self.mock_object(migration.LOG, 'warning') 

334 

335 # run 

336 self.helper.cleanup_new_instance(self.share_instance) 

337 

338 # asserts 

339 self.helper.delete_instance_and_wait.assert_called_once_with( 

340 self.share_instance) 

341 

342 if exc: 

343 self.assertEqual(1, migration.LOG.warning.call_count) 

344 

345 @ddt.data(None, Exception('fake')) 

346 def test_cleanup_access_rules(self, exc): 

347 

348 # mocks 

349 server = db_utils.create_share_server() 

350 self.mock_object(self.helper, 'revert_access_rules', 

351 mock.Mock(side_effect=exc)) 

352 

353 self.mock_object(migration.LOG, 'warning') 

354 

355 # run 

356 self.helper.cleanup_access_rules(self.share_instance, server) 

357 

358 # asserts 

359 self.helper.revert_access_rules.assert_called_once_with( 

360 self.share_instance, server, None) 

361 

362 if exc: 

363 self.assertEqual(1, migration.LOG.warning.call_count)