Coverage for manila/tests/share/drivers/hitachi/hsp/test_driver.py: 100%

234 statements  

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

1# Copyright (c) 2016 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 

16from unittest import mock 

17 

18import ddt 

19from oslo_config import cfg 

20 

21from manila import exception 

22import manila.share.configuration 

23import manila.share.driver 

24from manila.share.drivers.hitachi.hsp import driver 

25from manila.share.drivers.hitachi.hsp import rest 

26from manila import test 

27from manila.tests import fake_share 

28from manila.tests.share.drivers.hitachi.hsp import fakes 

29 

30from manila.common import constants 

31from oslo_utils import units 

32 

33CONF = cfg.CONF 

34 

35 

36@ddt.ddt 

37class HitachiHSPTestCase(test.TestCase): 

38 def setUp(self): 

39 super(HitachiHSPTestCase, self).setUp() 

40 CONF.set_default('driver_handles_share_servers', False) 

41 CONF.hitachi_hsp_host = '172.24.47.190' 

42 CONF.hitachi_hsp_username = 'hsp_user' 

43 CONF.hitachi_hsp_password = 'hsp_password' 

44 CONF.hitachi_hsp_job_timeout = 300 

45 

46 self.fake_el = [{ 

47 "path": CONF.hitachi_hsp_host + ":/fakeinstanceid", 

48 "metadata": {}, 

49 "is_admin_only": False, 

50 }] 

51 self.fake_share = fake_share.fake_share(share_proto='nfs') 

52 self.fake_share_instance = fake_share.fake_share_instance( 

53 base_share=self.fake_share, export_locations=self.fake_el) 

54 

55 self.fake_conf = manila.share.configuration.Configuration(None) 

56 self.fake_private_storage = mock.Mock() 

57 self.mock_object(rest.HSPRestBackend, "get_cluster", 

58 mock.Mock(return_value=fakes.hsp_cluster)) 

59 self._driver = driver.HitachiHSPDriver( 

60 configuration=self.fake_conf, 

61 private_storage=self.fake_private_storage) 

62 self._driver.backend_name = "HSP" 

63 self.mock_log = self.mock_object(driver, 'LOG') 

64 

65 @ddt.data(None, exception.HSPBackendException( 

66 message="Duplicate NFS access rule exists.")) 

67 def test_update_access_add(self, add_rule): 

68 access = { 

69 'access_type': 'ip', 

70 'access_to': '172.24.10.10', 

71 'access_level': 'rw', 

72 } 

73 

74 access_list = [access] 

75 

76 self.mock_object(rest.HSPRestBackend, "get_file_system", 

77 mock.Mock(return_value=fakes.file_system)) 

78 self.mock_object(rest.HSPRestBackend, "get_share", 

79 mock.Mock(return_value=fakes.share)) 

80 self.mock_object(rest.HSPRestBackend, "add_access_rule", mock.Mock( 

81 side_effect=add_rule)) 

82 

83 self._driver.update_access('context', self.fake_share_instance, [], 

84 access_list, [], []) 

85 

86 self.assertTrue(self.mock_log.debug.called) 

87 

88 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

89 self.fake_share_instance['id']) 

90 rest.HSPRestBackend.get_share.assert_called_once_with( 

91 fakes.file_system['id']) 

92 rest.HSPRestBackend.add_access_rule.assert_called_once_with( 

93 fakes.share['id'], access['access_to'], 

94 (access['access_level'] == constants.ACCESS_LEVEL_RW)) 

95 

96 def test_update_access_add_exception(self): 

97 access = { 

98 'access_type': 'ip', 

99 'access_to': '172.24.10.10', 

100 'access_level': 'rw', 

101 } 

102 

103 access_list = [access] 

104 

105 self.mock_object(rest.HSPRestBackend, "get_file_system", 

106 mock.Mock(return_value=fakes.file_system)) 

107 self.mock_object(rest.HSPRestBackend, "get_share", 

108 mock.Mock(return_value=fakes.share)) 

109 self.mock_object(rest.HSPRestBackend, "add_access_rule", 

110 mock.Mock(side_effect=exception.HSPBackendException( 

111 message="HSP Backend Exception: error adding " 

112 "rule."))) 

113 

114 self.assertRaises(exception.HSPBackendException, 

115 self._driver.update_access, 'context', 

116 self.fake_share_instance, [], access_list, [], []) 

117 

118 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

119 self.fake_share_instance['id']) 

120 rest.HSPRestBackend.get_share.assert_called_once_with( 

121 fakes.file_system['id']) 

122 rest.HSPRestBackend.add_access_rule.assert_called_once_with( 

123 fakes.share['id'], access['access_to'], 

124 (access['access_level'] == constants.ACCESS_LEVEL_RW)) 

125 

126 def test_update_access_recovery(self): 

127 access1 = { 

128 'access_type': 'ip', 

129 'access_to': '172.24.10.10', 

130 'access_level': 'rw', 

131 } 

132 access2 = { 

133 'access_type': 'ip', 

134 'access_to': '188.100.20.10', 

135 'access_level': 'ro', 

136 } 

137 

138 access_list = [access1, access2] 

139 

140 self.mock_object(rest.HSPRestBackend, "get_file_system", 

141 mock.Mock(return_value=fakes.file_system)) 

142 self.mock_object(rest.HSPRestBackend, "get_share", 

143 mock.Mock(return_value=fakes.share)) 

144 self.mock_object(rest.HSPRestBackend, "get_access_rules", 

145 mock.Mock(side_effect=[fakes.hsp_rules, []])) 

146 self.mock_object(rest.HSPRestBackend, "delete_access_rule") 

147 self.mock_object(rest.HSPRestBackend, "add_access_rule") 

148 

149 self._driver.update_access('context', self.fake_share_instance, 

150 access_list, [], [], []) 

151 

152 self.assertTrue(self.mock_log.debug.called) 

153 

154 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

155 self.fake_share_instance['id']) 

156 rest.HSPRestBackend.get_share.assert_called_once_with( 

157 fakes.file_system['id']) 

158 rest.HSPRestBackend.get_access_rules.assert_has_calls([ 

159 mock.call(fakes.share['id'])]) 

160 rest.HSPRestBackend.delete_access_rule.assert_called_once_with( 

161 fakes.share['id'], 

162 fakes.share['id'] + fakes.hsp_rules[0]['host-specification']) 

163 rest.HSPRestBackend.add_access_rule.assert_has_calls([ 

164 mock.call(fakes.share['id'], access1['access_to'], True), 

165 mock.call(fakes.share['id'], access2['access_to'], False) 

166 ], any_order=True) 

167 

168 @ddt.data(None, exception.HSPBackendException( 

169 message="No matching access rule found.")) 

170 def test_update_access_delete(self, delete_rule): 

171 access1 = { 

172 'access_type': 'ip', 

173 'access_to': '172.24.44.200', 

174 'access_level': 'rw', 

175 } 

176 access2 = { 

177 'access_type': 'something', 

178 'access_to': '188.100.20.10', 

179 'access_level': 'ro', 

180 } 

181 

182 delete_rules = [access1, access2] 

183 

184 self.mock_object(rest.HSPRestBackend, "get_file_system", 

185 mock.Mock(return_value=fakes.file_system)) 

186 self.mock_object(rest.HSPRestBackend, "get_share", 

187 mock.Mock(return_value=fakes.share)) 

188 self.mock_object(rest.HSPRestBackend, "delete_access_rule", 

189 mock.Mock(side_effect=delete_rule)) 

190 self.mock_object(rest.HSPRestBackend, "get_access_rules", 

191 mock.Mock(return_value=fakes.hsp_rules)) 

192 

193 self._driver.update_access('context', self.fake_share_instance, [], [], 

194 delete_rules, []) 

195 

196 self.assertTrue(self.mock_log.debug.called) 

197 

198 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

199 self.fake_share_instance['id']) 

200 rest.HSPRestBackend.get_share.assert_called_once_with( 

201 fakes.file_system['id']) 

202 rest.HSPRestBackend.delete_access_rule.assert_called_once_with( 

203 fakes.share['id'], fakes.hsp_rules[0]['name']) 

204 rest.HSPRestBackend.get_access_rules.assert_called_once_with( 

205 fakes.share['id']) 

206 

207 def test_update_access_delete_exception(self): 

208 access1 = { 

209 'access_type': 'ip', 

210 'access_to': '172.24.10.10', 

211 'access_level': 'rw', 

212 } 

213 access2 = { 

214 'access_type': 'something', 

215 'access_to': '188.100.20.10', 

216 'access_level': 'ro', 

217 } 

218 

219 delete_rules = [access1, access2] 

220 

221 self.mock_object(rest.HSPRestBackend, "get_file_system", 

222 mock.Mock(return_value=fakes.file_system)) 

223 self.mock_object(rest.HSPRestBackend, "get_share", 

224 mock.Mock(return_value=fakes.share)) 

225 self.mock_object(rest.HSPRestBackend, "delete_access_rule", 

226 mock.Mock(side_effect=exception.HSPBackendException( 

227 message="HSP Backend Exception: error deleting " 

228 "rule."))) 

229 self.mock_object(rest.HSPRestBackend, 'get_access_rules', 

230 mock.Mock(return_value=[])) 

231 

232 self.assertRaises(exception.HSPBackendException, 

233 self._driver.update_access, 'context', 

234 self.fake_share_instance, [], [], delete_rules, []) 

235 

236 self.assertTrue(self.mock_log.debug.called) 

237 

238 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

239 self.fake_share_instance['id']) 

240 rest.HSPRestBackend.get_share.assert_called_once_with( 

241 fakes.file_system['id']) 

242 rest.HSPRestBackend.delete_access_rule.assert_called_once_with( 

243 fakes.share['id'], fakes.share['id'] + access1['access_to']) 

244 rest.HSPRestBackend.get_access_rules.assert_called_once_with( 

245 fakes.share['id']) 

246 

247 @ddt.data(True, False) 

248 def test_update_access_ip_exception(self, is_recovery): 

249 access = { 

250 'access_type': 'something', 

251 'access_to': '172.24.10.10', 

252 'access_level': 'rw', 

253 } 

254 

255 access_list = [access] 

256 

257 self.mock_object(rest.HSPRestBackend, "get_file_system", 

258 mock.Mock(return_value=fakes.file_system)) 

259 self.mock_object(rest.HSPRestBackend, "get_share", 

260 mock.Mock(return_value=fakes.share)) 

261 self.mock_object(rest.HSPRestBackend, "get_access_rules", 

262 mock.Mock(return_value=fakes.hsp_rules)) 

263 

264 if is_recovery: 

265 access_args = [access_list, [], [], []] 

266 else: 

267 access_args = [[], access_list, [], []] 

268 

269 self.assertRaises(exception.InvalidShareAccess, 

270 self._driver.update_access, 'context', 

271 self.fake_share_instance, *access_args) 

272 

273 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

274 self.fake_share_instance['id']) 

275 rest.HSPRestBackend.get_share.assert_called_once_with( 

276 fakes.file_system['id']) 

277 

278 if is_recovery: 

279 rest.HSPRestBackend.get_access_rules.assert_called_once_with( 

280 fakes.share['id']) 

281 

282 def test_update_access_not_found_exception(self): 

283 access_list = [] 

284 

285 self.mock_object(rest.HSPRestBackend, "get_file_system", mock.Mock( 

286 side_effect=exception.HSPItemNotFoundException(msg='fake'))) 

287 

288 self.assertRaises(exception.ShareResourceNotFound, 

289 self._driver.update_access, 'context', 

290 self.fake_share_instance, access_list, [], [], []) 

291 

292 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

293 self.fake_share_instance['id']) 

294 

295 def test_create_share(self): 

296 self.mock_object(rest.HSPRestBackend, "add_file_system", mock.Mock()) 

297 self.mock_object(rest.HSPRestBackend, "get_file_system", 

298 mock.Mock(return_value=fakes.file_system)) 

299 self.mock_object(rest.HSPRestBackend, "add_share", mock.Mock()) 

300 

301 result = self._driver.create_share('context', self.fake_share_instance) 

302 

303 self.assertEqual(self.fake_el, result) 

304 self.assertTrue(self.mock_log.debug.called) 

305 

306 rest.HSPRestBackend.add_file_system.assert_called_once_with( 

307 self.fake_share_instance['id'], 

308 self.fake_share_instance['size'] * units.Gi) 

309 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

310 self.fake_share_instance['id']) 

311 rest.HSPRestBackend.add_share.assert_called_once_with( 

312 self.fake_share_instance['id'], fakes.file_system['id']) 

313 

314 def test_create_share_export_error(self): 

315 self.mock_object(rest.HSPRestBackend, "add_file_system", mock.Mock()) 

316 self.mock_object(rest.HSPRestBackend, "get_file_system", 

317 mock.Mock(return_value=fakes.file_system)) 

318 self.mock_object(rest.HSPRestBackend, "add_share", mock.Mock( 

319 side_effect=exception.HSPBackendException(msg='fake'))) 

320 self.mock_object(rest.HSPRestBackend, "delete_file_system", 

321 mock.Mock()) 

322 

323 self.assertRaises(exception.HSPBackendException, 

324 self._driver.create_share, 'context', 

325 self.fake_share_instance) 

326 self.assertTrue(self.mock_log.debug.called) 

327 self.assertTrue(self.mock_log.exception.called) 

328 

329 rest.HSPRestBackend.add_file_system.assert_called_once_with( 

330 self.fake_share_instance['id'], 

331 self.fake_share_instance['size'] * units.Gi) 

332 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

333 self.fake_share_instance['id']) 

334 rest.HSPRestBackend.add_share.assert_called_once_with( 

335 self.fake_share_instance['id'], fakes.file_system['id']) 

336 rest.HSPRestBackend.delete_file_system.assert_called_once_with( 

337 fakes.file_system['id']) 

338 

339 def test_create_share_invalid_share_protocol(self): 

340 self.assertRaises(exception.InvalidShare, 

341 self._driver.create_share, 'context', 

342 fakes.invalid_share) 

343 

344 @ddt.data(None, exception.HSPBackendException( 

345 message="No matching access rule found.")) 

346 def test_delete_share(self, delete_rule): 

347 self.mock_object(rest.HSPRestBackend, "get_file_system", 

348 mock.Mock(return_value=fakes.file_system)) 

349 self.mock_object(rest.HSPRestBackend, "get_share", 

350 mock.Mock(return_value=fakes.share)) 

351 self.mock_object(rest.HSPRestBackend, "delete_share") 

352 self.mock_object(rest.HSPRestBackend, "delete_file_system") 

353 self.mock_object(rest.HSPRestBackend, "get_access_rules", 

354 mock.Mock(return_value=[fakes.hsp_rules[0]])) 

355 self.mock_object(rest.HSPRestBackend, "delete_access_rule", mock.Mock( 

356 side_effect=[exception.HSPBackendException( 

357 message="No matching access rule found."), delete_rule])) 

358 

359 self._driver.delete_share('context', self.fake_share_instance) 

360 

361 self.assertTrue(self.mock_log.debug.called) 

362 

363 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

364 self.fake_share_instance['id']) 

365 rest.HSPRestBackend.get_share.assert_called_once_with( 

366 fakes.file_system['id']) 

367 rest.HSPRestBackend.delete_share.assert_called_once_with( 

368 fakes.share['id']) 

369 rest.HSPRestBackend.delete_file_system.assert_called_once_with( 

370 fakes.file_system['id']) 

371 rest.HSPRestBackend.get_access_rules.assert_called_once_with( 

372 fakes.share['id']) 

373 rest.HSPRestBackend.delete_access_rule.assert_called_once_with( 

374 fakes.share['id'], fakes.hsp_rules[0]['name']) 

375 

376 def test_delete_share_rule_exception(self): 

377 self.mock_object(rest.HSPRestBackend, "get_file_system", 

378 mock.Mock(return_value=fakes.file_system)) 

379 self.mock_object(rest.HSPRestBackend, "get_share", 

380 mock.Mock(return_value=fakes.share)) 

381 self.mock_object(rest.HSPRestBackend, "get_access_rules", 

382 mock.Mock(return_value=[fakes.hsp_rules[0]])) 

383 self.mock_object(rest.HSPRestBackend, "delete_access_rule", 

384 mock.Mock(side_effect=exception.HSPBackendException( 

385 message="Internal Server Error."))) 

386 

387 self.assertRaises(exception.HSPBackendException, 

388 self._driver.delete_share, 'context', 

389 self.fake_share_instance) 

390 

391 self.assertTrue(self.mock_log.debug.called) 

392 

393 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

394 self.fake_share_instance['id']) 

395 rest.HSPRestBackend.get_share.assert_called_once_with( 

396 fakes.file_system['id']) 

397 rest.HSPRestBackend.get_access_rules.assert_called_once_with( 

398 fakes.share['id']) 

399 rest.HSPRestBackend.delete_access_rule.assert_called_once_with( 

400 fakes.share['id'], fakes.hsp_rules[0]['name']) 

401 

402 def test_delete_share_already_deleted(self): 

403 self.mock_object(rest.HSPRestBackend, "get_file_system", mock.Mock( 

404 side_effect=exception.HSPItemNotFoundException(msg='fake'))) 

405 

406 self.mock_object(driver.LOG, "info") 

407 

408 self._driver.delete_share('context', self.fake_share_instance) 

409 

410 self.assertTrue(self.mock_log.info.called) 

411 

412 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

413 self.fake_share_instance['id']) 

414 

415 def test_extend_share(self): 

416 new_size = 2 

417 

418 self.mock_object(rest.HSPRestBackend, "get_file_system", 

419 mock.Mock(return_value=fakes.file_system)) 

420 self.mock_object(rest.HSPRestBackend, "resize_file_system", 

421 mock.Mock()) 

422 

423 self._driver.extend_share(self.fake_share_instance, new_size) 

424 

425 self.assertTrue(self.mock_log.info.called) 

426 

427 rest.HSPRestBackend.get_cluster.assert_called_once_with() 

428 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

429 self.fake_share_instance['id']) 

430 rest.HSPRestBackend.resize_file_system.assert_called_once_with( 

431 fakes.file_system['id'], new_size * units.Gi) 

432 

433 def test_extend_share_with_no_available_space_in_fs(self): 

434 new_size = 150 

435 

436 self.assertRaises(exception.HSPBackendException, 

437 self._driver.extend_share, self.fake_share_instance, 

438 new_size) 

439 

440 rest.HSPRestBackend.get_cluster.assert_called_once_with() 

441 

442 def test_shrink_share(self): 

443 new_size = 70 

444 

445 self.mock_object(rest.HSPRestBackend, "get_file_system", 

446 mock.Mock(return_value=fakes.file_system)) 

447 self.mock_object(rest.HSPRestBackend, "resize_file_system", 

448 mock.Mock()) 

449 

450 self._driver.shrink_share(self.fake_share_instance, new_size) 

451 

452 self.assertTrue(self.mock_log.info.called) 

453 

454 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

455 self.fake_share_instance['id']) 

456 rest.HSPRestBackend.resize_file_system.assert_called_once_with( 

457 fakes.file_system['id'], new_size * units.Gi) 

458 

459 def test_shrink_share_new_size_lower_than_usage(self): 

460 new_size = 20 

461 

462 self.mock_object(rest.HSPRestBackend, "get_file_system", 

463 mock.Mock(return_value=fakes.file_system)) 

464 

465 self.assertRaises(exception.ShareShrinkingPossibleDataLoss, 

466 self._driver.shrink_share, self.fake_share_instance, 

467 new_size) 

468 

469 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

470 self.fake_share_instance['id']) 

471 

472 def test_manage_existing(self): 

473 self.mock_object(self.fake_private_storage, "update") 

474 self.mock_object(rest.HSPRestBackend, "get_share", 

475 mock.Mock(return_value=fakes.share)) 

476 self.mock_object(rest.HSPRestBackend, "rename_file_system", 

477 mock.Mock()) 

478 self.mock_object(rest.HSPRestBackend, "get_file_system", 

479 mock.Mock(return_value=fakes.file_system)) 

480 

481 result = self._driver.manage_existing(self.fake_share_instance, 

482 'option') 

483 

484 expected = { 

485 'size': fakes.file_system['properties']['quota'] / units.Gi, 

486 'export_locations': self.fake_el, 

487 } 

488 

489 self.assertTrue(self.mock_log.info.called) 

490 self.assertEqual(expected, result) 

491 

492 rest.HSPRestBackend.get_share.assert_called_once_with( 

493 name=self.fake_share_instance['id']) 

494 rest.HSPRestBackend.rename_file_system.assert_called_once_with( 

495 fakes.file_system['id'], self.fake_share_instance['id']) 

496 rest.HSPRestBackend.get_file_system.assert_called_once_with( 

497 self.fake_share_instance['id']) 

498 

499 def test_manage_existing_wrong_share_id(self): 

500 self.mock_object(rest.HSPRestBackend, "get_share", mock.Mock( 

501 side_effect=exception.HSPItemNotFoundException(msg='fake'))) 

502 

503 self.assertRaises(exception.ManageInvalidShare, 

504 self._driver.manage_existing, 

505 self.fake_share_instance, 

506 'option') 

507 

508 rest.HSPRestBackend.get_share.assert_called_once_with( 

509 name=self.fake_share_instance['id']) 

510 

511 def test_unmanage(self): 

512 self.mock_object(self.fake_private_storage, "get", 

513 mock.Mock( 

514 return_value='original_name')) 

515 self.mock_object(self.fake_private_storage, "delete") 

516 

517 self._driver.unmanage(self.fake_share_instance) 

518 

519 self.assertTrue(self.mock_log.info.called) 

520 

521 def test__update_share_stats(self): 

522 mock__update_share_stats = self.mock_object( 

523 manila.share.driver.ShareDriver, '_update_share_stats') 

524 self.mock_object(self.fake_private_storage, 'get', mock.Mock( 

525 return_value={'provisioned': 0} 

526 )) 

527 

528 self._driver._update_share_stats() 

529 

530 rest.HSPRestBackend.get_cluster.assert_called_once_with() 

531 mock__update_share_stats.assert_called_once_with(fakes.stats_data) 

532 self.assertTrue(self.mock_log.info.called) 

533 

534 def test_get_default_filter_function(self): 

535 expected = "share.size >= 128" 

536 

537 actual = self._driver.get_default_filter_function() 

538 

539 self.assertEqual(expected, actual)