Coverage for manila/tests/share/drivers/zfssa/test_zfssashare.py: 100%

243 statements  

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

1# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); you may 

4# not use this file except in compliance with the License. You may obtain 

5# a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

12# License for the specific language governing permissions and limitations 

13# under the License. 

14""" 

15Unit tests for Oracle's ZFSSA Manila driver. 

16""" 

17from unittest import mock 

18 

19from oslo_config import cfg 

20from oslo_utils import units 

21 

22from manila import context 

23from manila import exception 

24from manila.share import configuration as conf 

25from manila.share.drivers.zfssa import zfssashare 

26from manila import test 

27from manila.tests import fake_zfssa 

28 

29 

30CONF = cfg.CONF 

31 

32 

33class ZFSSAShareDriverTestCase(test.TestCase): 

34 """Tests ZFSSAShareDriver.""" 

35 

36 share = { 

37 'id': 'fakeid', 

38 'name': 'fakename', 

39 'size': 1, 

40 'share_proto': 'NFS', 

41 'export_location': '/mnt/nfs/volume-00002', 

42 } 

43 

44 share2 = { 

45 'id': 'fakeid2', 

46 'name': 'fakename2', 

47 'size': 4, 

48 'share_proto': 'CIFS', 

49 'export_location': '/mnt/nfs/volume-00003', 

50 'space_data': 3006477107 

51 } 

52 

53 snapshot = { 

54 'id': 'fakesnapshotid', 

55 'share_name': 'fakename', 

56 'share_id': 'fakeid', 

57 'name': 'fakesnapshotname', 

58 'share_size': 1, 

59 'share_proto': 'NFS', 

60 } 

61 

62 access = { 

63 'id': 'fakeaccid', 

64 'access_type': 'ip', 

65 'access_to': '10.0.0.2', 

66 'state': 'active', 

67 } 

68 

69 @mock.patch.object(zfssashare, 'factory_zfssa') 

70 def setUp(self, _factory_zfssa): 

71 super(ZFSSAShareDriverTestCase, self).setUp() 

72 self._create_fake_config() 

73 lcfg = self.configuration 

74 self.mountpoint = '/export/' + lcfg.zfssa_nas_mountpoint 

75 _factory_zfssa.return_value = fake_zfssa.FakeZFSSA() 

76 _factory_zfssa.set_host(lcfg.zfssa_host) 

77 _factory_zfssa.login(lcfg.zfssa_auth_user) 

78 self._context = context.get_admin_context() 

79 self._driver = zfssashare.ZFSSAShareDriver(False, configuration=lcfg) 

80 self._driver.do_setup(self._context) 

81 

82 self.fake_proto_share = { 

83 'id': self.share['id'], 

84 'share_proto': 'fake_proto', 

85 'export_locations': [{'path': self.share['export_location']}], 

86 } 

87 

88 self.test_share = { 

89 'id': self.share['id'], 

90 'share_proto': 'NFS', 

91 'export_locations': [{'path': self.share['export_location']}], 

92 } 

93 

94 self.test_share2 = { 

95 'id': self.share2['id'], 

96 'share_proto': 'CIFS', 

97 'export_locations': [{'path': self.share2['export_location']}], 

98 } 

99 

100 self.driver_options = {'zfssa_name': self.share['name']} 

101 

102 def _create_fake_config(self): 

103 def _safe_get(opt): 

104 return getattr(self.configuration, opt) 

105 

106 self.configuration = mock.Mock(spec=conf.Configuration) 

107 self.configuration.safe_get = mock.Mock(side_effect=_safe_get) 

108 self.configuration.zfssa_host = '1.1.1.1' 

109 self.configuration.zfssa_data_ip = '1.1.1.1' 

110 self.configuration.zfssa_auth_user = 'user' 

111 self.configuration.zfssa_auth_password = 'passwd' 

112 self.configuration.zfssa_pool = 'pool' 

113 self.configuration.zfssa_project = 'project' 

114 self.configuration.zfssa_nas_mountpoint = 'project' 

115 self.configuration.zfssa_nas_checksum = 'fletcher4' 

116 self.configuration.zfssa_nas_logbias = 'latency' 

117 self.configuration.zfssa_nas_compression = 'off' 

118 self.configuration.zfssa_nas_vscan = 'false' 

119 self.configuration.zfssa_nas_rstchown = 'true' 

120 self.configuration.zfssa_nas_quota_snap = 'true' 

121 self.configuration.zfssa_rest_timeout = 60 

122 self.configuration.network_config_group = 'fake_network_config_group' 

123 self.configuration.admin_network_config_group = ( 

124 'fake_admin_network_config_group') 

125 self.configuration.driver_handles_share_servers = False 

126 self.configuration.zfssa_manage_policy = 'strict' 

127 

128 def test_create_share(self): 

129 self.mock_object(self._driver.zfssa, 'create_share') 

130 self.mock_object(self._driver, '_export_location') 

131 lcfg = self.configuration 

132 arg = { 

133 'host': lcfg.zfssa_data_ip, 

134 'mountpoint': self.mountpoint, 

135 'name': self.share['id'], 

136 } 

137 location = ("%(host)s:%(mountpoint)s/%(name)s" % arg) 

138 self._driver._export_location.return_value = location 

139 arg = self._driver.create_arg(self.share['size']) 

140 arg.update(self._driver.default_args) 

141 arg.update({'name': self.share['id']}) 

142 ret = self._driver.create_share(self._context, self.share) 

143 self._driver.zfssa.create_share.assert_called_with(lcfg.zfssa_pool, 

144 lcfg.zfssa_project, 

145 arg) 

146 self.assertEqual(location, ret) 

147 self.assertEqual(1, self._driver.zfssa.create_share.call_count) 

148 self.assertEqual(1, self._driver._export_location.call_count) 

149 

150 def test_create_share_from_snapshot(self): 

151 self.mock_object(self._driver.zfssa, 'clone_snapshot') 

152 self.mock_object(self._driver, '_export_location') 

153 lcfg = self.configuration 

154 arg = { 

155 'host': lcfg.zfssa_data_ip, 

156 'mountpoint': self.mountpoint, 

157 'name': self.share['id'], 

158 } 

159 location = ("%(host)s:%(mountpoint)s/%(name)s" % arg) 

160 self._driver._export_location.return_value = location 

161 arg = self._driver.create_arg(self.share['size']) 

162 details = { 

163 'share': self.share['id'], 

164 'project': lcfg.zfssa_project, 

165 } 

166 arg.update(details) 

167 ret = self._driver.create_share_from_snapshot(self._context, 

168 self.share, 

169 self.snapshot) 

170 self.assertEqual(location, ret) 

171 self.assertEqual(1, self._driver.zfssa.clone_snapshot.call_count) 

172 self.assertEqual(1, self._driver._export_location.call_count) 

173 self._driver.zfssa.clone_snapshot.assert_called_with( 

174 lcfg.zfssa_pool, 

175 lcfg.zfssa_project, 

176 self.snapshot, 

177 self.share, 

178 arg) 

179 

180 def test_delete_share(self): 

181 self.mock_object(self._driver.zfssa, 'delete_share') 

182 self._driver.delete_share(self._context, self.share) 

183 self.assertEqual(1, self._driver.zfssa.delete_share.call_count) 

184 lcfg = self.configuration 

185 self._driver.zfssa.delete_share.assert_called_with(lcfg.zfssa_pool, 

186 lcfg.zfssa_project, 

187 self.share['id']) 

188 

189 def test_create_snapshot(self): 

190 self.mock_object(self._driver.zfssa, 'create_snapshot') 

191 lcfg = self.configuration 

192 self._driver.create_snapshot(self._context, self.snapshot) 

193 self.assertEqual(1, self._driver.zfssa.create_snapshot.call_count) 

194 self._driver.zfssa.create_snapshot.assert_called_with( 

195 lcfg.zfssa_pool, 

196 lcfg.zfssa_project, 

197 self.snapshot['share_id'], 

198 self.snapshot['id']) 

199 

200 def test_delete_snapshot(self): 

201 self.mock_object(self._driver.zfssa, 'delete_snapshot') 

202 self._driver.delete_snapshot(self._context, self.snapshot) 

203 self.assertEqual(1, self._driver.zfssa.delete_snapshot.call_count) 

204 

205 def test_delete_snapshot_negative(self): 

206 self.mock_object(self._driver.zfssa, 'has_clones') 

207 self._driver.zfssa.has_clones.return_value = True 

208 self.assertRaises(exception.ShareSnapshotIsBusy, 

209 self._driver.delete_snapshot, 

210 self._context, 

211 self.snapshot) 

212 

213 def test_ensure_share(self): 

214 self.mock_object(self._driver.zfssa, 'get_share') 

215 lcfg = self.configuration 

216 self._driver.ensure_share(self._context, self.share) 

217 self.assertEqual(1, self._driver.zfssa.get_share.call_count) 

218 self._driver.zfssa.get_share.assert_called_with( 

219 lcfg.zfssa_pool, 

220 lcfg.zfssa_project, 

221 self.share['id']) 

222 

223 self._driver.zfssa.get_share.return_value = None 

224 self.assertRaises(exception.ManilaException, 

225 self._driver.ensure_share, 

226 self._context, 

227 self.share) 

228 

229 def test_allow_access(self): 

230 self.mock_object(self._driver.zfssa, 'allow_access_nfs') 

231 lcfg = self.configuration 

232 self._driver.allow_access(self._context, self.share, self.access) 

233 self.assertEqual(1, self._driver.zfssa.allow_access_nfs.call_count) 

234 self._driver.zfssa.allow_access_nfs.assert_called_with( 

235 lcfg.zfssa_pool, 

236 lcfg.zfssa_project, 

237 self.share['id'], 

238 self.access) 

239 

240 def test_deny_access(self): 

241 self.mock_object(self._driver.zfssa, 'deny_access_nfs') 

242 lcfg = self.configuration 

243 self._driver.deny_access(self._context, self.share, self.access) 

244 self.assertEqual(1, self._driver.zfssa.deny_access_nfs.call_count) 

245 self._driver.zfssa.deny_access_nfs.assert_called_with( 

246 lcfg.zfssa_pool, 

247 lcfg.zfssa_project, 

248 self.share['id'], 

249 self.access) 

250 

251 def test_extend_share_negative(self): 

252 self.mock_object(self._driver.zfssa, 'modify_share') 

253 new_size = 3 

254 # Not enough space in project, expect an exception: 

255 self.mock_object(self._driver.zfssa, 'get_project_stats') 

256 self._driver.zfssa.get_project_stats.return_value = 1 * units.Gi 

257 

258 self.assertRaises(exception.ShareExtendingError, 

259 self._driver.extend_share, 

260 self.share, 

261 new_size) 

262 

263 def test_extend_share(self): 

264 self.mock_object(self._driver.zfssa, 'modify_share') 

265 new_size = 3 

266 lcfg = self.configuration 

267 self.mock_object(self._driver.zfssa, 'get_project_stats') 

268 self._driver.zfssa.get_project_stats.return_value = 10 * units.Gi 

269 

270 arg = self._driver.create_arg(new_size) 

271 self._driver.extend_share(self.share, new_size) 

272 

273 self.assertEqual(1, self._driver.zfssa.modify_share.call_count) 

274 self._driver.zfssa.modify_share.assert_called_with( 

275 lcfg.zfssa_pool, 

276 lcfg.zfssa_project, 

277 self.share['id'], 

278 arg) 

279 

280 def test_shrink_share_negative(self): 

281 self.mock_object(self._driver.zfssa, 'modify_share') 

282 # Used space is larger than 2GB 

283 new_size = 2 

284 self.mock_object(self._driver.zfssa, 'get_share') 

285 self._driver.zfssa.get_share.return_value = self.share2 

286 

287 self.assertRaises(exception.ShareShrinkingPossibleDataLoss, 

288 self._driver.shrink_share, 

289 self.share2, 

290 new_size) 

291 

292 def test_shrink_share(self): 

293 self.mock_object(self._driver.zfssa, 'modify_share') 

294 new_size = 3 

295 lcfg = self.configuration 

296 self.mock_object(self._driver.zfssa, 'get_share') 

297 self._driver.zfssa.get_share.return_value = self.share2 

298 

299 arg = self._driver.create_arg(new_size) 

300 self._driver.shrink_share(self.share2, new_size) 

301 

302 self.assertEqual(1, self._driver.zfssa.modify_share.call_count) 

303 self._driver.zfssa.modify_share.assert_called_with( 

304 lcfg.zfssa_pool, 

305 lcfg.zfssa_project, 

306 self.share2['id'], 

307 arg) 

308 

309 def test_manage_invalid_option(self): 

310 self.mock_object(self._driver, '_get_share_details') 

311 

312 # zfssa_name not in driver_options: 

313 self.assertRaises(exception.ShareBackendException, 

314 self._driver.manage_existing, 

315 self.share, 

316 {}) 

317 

318 def test_manage_no_share_details(self): 

319 self.mock_object(self._driver, '_get_share_details') 

320 self._driver._get_share_details.side_effect = ( 

321 exception.ShareResourceNotFound(share_id=self.share['name'])) 

322 

323 self.assertRaises(exception.ShareResourceNotFound, 

324 self._driver.manage_existing, 

325 self.share, 

326 self.driver_options) 

327 

328 def test_manage_invalid_size(self): 

329 details = { 

330 'quota': 10, # 10 bytes 

331 'reservation': 10, 

332 } 

333 self.mock_object(self._driver, '_get_share_details') 

334 self._driver._get_share_details.return_value = details 

335 

336 self.mock_object(self._driver.zfssa, 'get_project_stats') 

337 self._driver.zfssa.get_project_stats.return_value = 900 

338 

339 # Share size is less than 1GB, but there is not enough free space 

340 self.assertRaises(exception.ManageInvalidShare, 

341 self._driver.manage_existing, 

342 self.test_share, 

343 self.driver_options) 

344 

345 def test_manage_invalid_protocol(self): 

346 self.mock_object(self._driver, '_get_share_details') 

347 self._driver._get_share_details.return_value = { 

348 'quota': self.share['size'] * units.Gi, 

349 'reservation': self.share['size'] * units.Gi, 

350 'custom:manila_managed': False, 

351 } 

352 

353 self.assertRaises(exception.ManageInvalidShare, 

354 self._driver.manage_existing, 

355 self.fake_proto_share, 

356 self.driver_options) 

357 

358 def test_manage_unmanage_no_schema(self): 

359 self.mock_object(self._driver, '_get_share_details') 

360 self._driver._get_share_details.return_value = {} 

361 

362 # Share does not have custom:manila_managed property 

363 # Test manage_existing(): 

364 self.assertRaises(exception.ManageInvalidShare, 

365 self._driver.manage_existing, 

366 self.test_share, 

367 self.driver_options) 

368 

369 # Test unmanage(): 

370 self.assertRaises(exception.UnmanageInvalidShare, 

371 self._driver.unmanage, 

372 self.test_share) 

373 

374 def test_manage_round_up_size(self): 

375 details = { 

376 'quota': 100, 

377 'reservation': 50, 

378 'custom:manila_managed': False, 

379 } 

380 self.mock_object(self._driver, '_get_share_details') 

381 self._driver._get_share_details.return_value = details 

382 

383 self.mock_object(self._driver.zfssa, 'get_project_stats') 

384 self._driver.zfssa.get_project_stats.return_value = 1 * units.Gi 

385 

386 ret = self._driver.manage_existing(self.test_share, 

387 self.driver_options) 

388 

389 # Expect share size is 1GB 

390 self.assertEqual(1, ret['size']) 

391 

392 def test_manage_not_enough_space(self): 

393 details = { 

394 'quota': 3.5 * units.Gi, 

395 'reservation': 3.5 * units.Gi, 

396 'custom:manila_managed': False, 

397 } 

398 self.mock_object(self._driver, '_get_share_details') 

399 self._driver._get_share_details.return_value = details 

400 

401 self.mock_object(self._driver.zfssa, 'get_project_stats') 

402 self._driver.zfssa.get_project_stats.return_value = 0.1 * units.Gi 

403 

404 self.assertRaises(exception.ManageInvalidShare, 

405 self._driver.manage_existing, 

406 self.test_share, 

407 self.driver_options) 

408 

409 def test_manage_unmanage_NFS(self): 

410 lcfg = self.configuration 

411 details = { 

412 # Share size is 1GB 

413 'quota': self.share['size'] * units.Gi, 

414 'reservation': self.share['size'] * units.Gi, 

415 'custom:manila_managed': False, 

416 } 

417 arg = { 

418 'host': lcfg.zfssa_data_ip, 

419 'mountpoint': self.share['export_location'], 

420 'name': self.share['id'], 

421 } 

422 export_loc = "%(host)s:%(mountpoint)s/%(name)s" % arg 

423 self.mock_object(self._driver, '_get_share_details') 

424 self._driver._get_share_details.return_value = details 

425 

426 ret = self._driver.manage_existing(self.test_share, 

427 self.driver_options) 

428 

429 self.assertEqual(export_loc, ret['export_locations']) 

430 self.assertEqual(1, ret['size']) 

431 

432 def test_manage_unmanage_CIFS(self): 

433 lcfg = self.configuration 

434 details = { 

435 # Share size is 1GB 

436 'quota': self.share2['size'] * units.Gi, 

437 'reservation': self.share2['size'] * units.Gi, 

438 'custom:manila_managed': False, 

439 } 

440 arg = { 

441 'host': lcfg.zfssa_data_ip, 

442 'name': self.share2['id'], 

443 } 

444 export_loc = "\\\\%(host)s\\%(name)s" % arg 

445 self.mock_object(self._driver, '_get_share_details') 

446 self._driver._get_share_details.return_value = details 

447 

448 ret = self._driver.manage_existing(self.test_share2, 

449 self.driver_options) 

450 

451 self.assertEqual(export_loc, ret['export_locations']) 

452 self.assertEqual(4, ret['size']) 

453 

454 def test_unmanage_NFS(self): 

455 self.mock_object(self._driver.zfssa, 'modify_share') 

456 lcfg = self.configuration 

457 details = { 

458 'quota': self.share['size'] * units.Gi, 

459 'reservation': self.share['size'] * units.Gi, 

460 'custom:manila_managed': True, 

461 } 

462 

463 arg = { 

464 'custom:manila_managed': False, 

465 'sharenfs': 'off', 

466 } 

467 

468 self.mock_object(self._driver, '_get_share_details') 

469 self._driver._get_share_details.return_value = details 

470 

471 self._driver.unmanage(self.test_share) 

472 

473 self._driver.zfssa.modify_share.assert_called_with( 

474 lcfg.zfssa_pool, 

475 lcfg.zfssa_project, 

476 self.test_share['id'], 

477 arg) 

478 

479 def test_unmanage_CIFS(self): 

480 self.mock_object(self._driver.zfssa, 'modify_share') 

481 lcfg = self.configuration 

482 details = { 

483 'quota': self.share2['size'] * units.Gi, 

484 'reservation': self.share2['size'] * units.Gi, 

485 'custom:manila_managed': True, 

486 } 

487 

488 arg = { 

489 'custom:manila_managed': False, 

490 'sharesmb': 'off', 

491 } 

492 

493 self.mock_object(self._driver, '_get_share_details') 

494 self._driver._get_share_details.return_value = details 

495 

496 self._driver.unmanage(self.test_share2) 

497 

498 self._driver.zfssa.modify_share.assert_called_with( 

499 lcfg.zfssa_pool, 

500 lcfg.zfssa_project, 

501 self.test_share2['id'], 

502 arg) 

503 

504 def test_verify_share_to_manage_loose_policy(self): 

505 # Temporarily change policy to loose 

506 self.configuration.zfssa_manage_policy = 'loose' 

507 

508 ret = self._driver._verify_share_to_manage('sharename', {}) 

509 

510 self.assertIsNone(ret) 

511 # Change it back to strict 

512 self.configuration.zfssa_manage_policy = 'strict' 

513 

514 def test_verify_share_to_manage_no_property(self): 

515 self.configuration.zfssa_manage_policy = 'strict' 

516 self.assertRaises(exception.ManageInvalidShare, 

517 self._driver._verify_share_to_manage, 

518 'sharename', 

519 {}) 

520 

521 def test_verify_share_to_manage_alredy_managed(self): 

522 details = {'custom:manila_managed': True} 

523 

524 self.assertRaises(exception.ManageInvalidShare, 

525 self._driver._verify_share_to_manage, 

526 'sharename', 

527 details)