Coverage for manila/tests/share/drivers/hpe/test_hpe_3par_driver.py: 99%

329 statements  

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

1# Copyright 2015 Hewlett Packard Enterprise Development LP 

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 

15from copy import deepcopy 

16import sys 

17from unittest import mock 

18 

19import ddt 

20if 'hpe3parclient' not in sys.modules: 20 ↛ 23line 20 didn't jump to line 23 because the condition on line 20 was always true

21 sys.modules['hpe3parclient'] = mock.Mock() 

22 

23from manila import exception 

24from manila.share.drivers.hpe import hpe_3par_driver as hpe3pardriver 

25from manila.share.drivers.hpe import hpe_3par_mediator as hpe3parmediator 

26from manila import test 

27from manila.tests.share.drivers.hpe import test_hpe_3par_constants as constants 

28 

29 

30@ddt.ddt 

31class HPE3ParDriverFPGTestCase(test.TestCase): 

32 

33 @ddt.data((-1, 4), 

34 (0, 5), 

35 (0, -1)) 

36 @ddt.unpack 

37 def test_FPG_init_args_failure(self, min_ip, max_ip): 

38 self.assertRaises(exception.HPE3ParInvalid, 

39 hpe3pardriver.FPG, min_ip, max_ip) 

40 

41 @ddt.data(('invalid_ip_fpg, 10.256.0.1', 0, 4), 

42 (None, 0, 4), 

43 (' ', 0, 4), 

44 ('', 0, 4), 

45 ('max_ip_fpg, 10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.4, 10.0.0.5', 

46 0, 4), 

47 ('min_1_ip_fpg', 1, 4)) 

48 @ddt.unpack 

49 def test_FPG_type_failures(self, value, min_ip, max_ip): 

50 fpg_type_obj = hpe3pardriver.FPG(min_ip=min_ip, max_ip=max_ip) 

51 self.assertRaises(exception.HPE3ParInvalid, fpg_type_obj, value) 

52 

53 @ddt.data(('samplefpg, 10.0.0.1', {'samplefpg': ['10.0.0.1']}), 

54 ('samplefpg', {'samplefpg': []}), 

55 ('samplefpg, 10.0.0.1, 10.0.0.2', 

56 {'samplefpg': ['10.0.0.1', '10.0.0.2']})) 

57 @ddt.unpack 

58 def test_FPG_type_success(self, value, expected_fpg): 

59 fpg_type_obj = hpe3pardriver.FPG() 

60 fpg = fpg_type_obj(value) 

61 self.assertEqual(expected_fpg, fpg) 

62 

63 

64@ddt.ddt 

65class HPE3ParDriverTestCase(test.TestCase): 

66 

67 def setUp(self): 

68 super(HPE3ParDriverTestCase, self).setUp() 

69 

70 # Create a mock configuration with attributes and a safe_get() 

71 self.conf = mock.Mock() 

72 self.conf.driver_handles_share_servers = True 

73 self.conf.hpe3par_debug = constants.EXPECTED_HPE_DEBUG 

74 self.conf.hpe3par_username = constants.USERNAME 

75 self.conf.hpe3par_password = constants.PASSWORD 

76 self.conf.hpe3par_api_url = constants.API_URL 

77 self.conf.hpe3par_san_login = constants.SAN_LOGIN 

78 self.conf.hpe3par_san_password = constants.SAN_PASSWORD 

79 self.conf.hpe3par_san_ip = constants.EXPECTED_IP_1234 

80 self.conf.hpe3par_fpg = constants.EXPECTED_FPG_CONF 

81 self.conf.hpe3par_san_ssh_port = constants.PORT 

82 self.conf.ssh_conn_timeout = constants.TIMEOUT 

83 self.conf.hpe3par_fstore_per_share = False 

84 self.conf.hpe3par_require_cifs_ip = False 

85 self.conf.hpe3par_cifs_admin_access_username = constants.USERNAME, 

86 self.conf.hpe3par_cifs_admin_access_password = constants.PASSWORD, 

87 self.conf.hpe3par_cifs_admin_access_domain = ( 

88 constants.EXPECTED_CIFS_DOMAIN), 

89 self.conf.hpe3par_share_mount_path = constants.EXPECTED_MOUNT_PATH, 

90 self.conf.my_ip = constants.EXPECTED_IP_1234 

91 self.conf.network_config_group = 'test_network_config_group' 

92 self.conf.admin_network_config_group = ( 

93 'test_admin_network_config_group') 

94 self.conf.filter_function = None 

95 self.conf.goodness_function = None 

96 

97 def safe_get(attr): 

98 try: 

99 return self.conf.__getattribute__(attr) 

100 except AttributeError: 

101 return None 

102 self.conf.safe_get = safe_get 

103 

104 self.real_hpe_3par_mediator = hpe3parmediator.HPE3ParMediator 

105 self.mock_object(hpe3parmediator, 'HPE3ParMediator') 

106 self.mock_mediator_constructor = hpe3parmediator.HPE3ParMediator 

107 self.mock_mediator = self.mock_mediator_constructor() 

108 # restore needed static methods 

109 self.mock_mediator.ensure_supported_protocol = ( 

110 self.real_hpe_3par_mediator.ensure_supported_protocol) 

111 self.mock_mediator.build_export_locations = ( 

112 self.real_hpe_3par_mediator.build_export_locations) 

113 

114 self.driver = hpe3pardriver.HPE3ParShareDriver( 

115 configuration=self.conf) 

116 

117 def test_driver_setup_success(self, 

118 get_vfs_ret_val=constants.EXPECTED_GET_VFS): 

119 """Driver do_setup without any errors.""" 

120 

121 self.mock_mediator.get_vfs.return_value = get_vfs_ret_val 

122 

123 self.driver.do_setup(None) 

124 conf = self.conf 

125 self.mock_mediator_constructor.assert_has_calls([ 

126 mock.call(hpe3par_san_ssh_port=conf.hpe3par_san_ssh_port, 

127 hpe3par_san_password=conf.hpe3par_san_password, 

128 hpe3par_username=conf.hpe3par_username, 

129 hpe3par_san_login=conf.hpe3par_san_login, 

130 hpe3par_debug=conf.hpe3par_debug, 

131 hpe3par_api_url=conf.hpe3par_api_url, 

132 hpe3par_password=conf.hpe3par_password, 

133 hpe3par_san_ip=conf.hpe3par_san_ip, 

134 hpe3par_fstore_per_share=conf.hpe3par_fstore_per_share, 

135 hpe3par_require_cifs_ip=conf.hpe3par_require_cifs_ip, 

136 hpe3par_cifs_admin_access_username=( 

137 conf.hpe3par_cifs_admin_access_username), 

138 hpe3par_cifs_admin_access_password=( 

139 conf.hpe3par_cifs_admin_access_password), 

140 hpe3par_cifs_admin_access_domain=( 

141 conf.hpe3par_cifs_admin_access_domain), 

142 hpe3par_share_mount_path=conf.hpe3par_share_mount_path, 

143 my_ip=self.conf.my_ip, 

144 ssh_conn_timeout=conf.ssh_conn_timeout)]) 

145 

146 self.mock_mediator.assert_has_calls([ 

147 mock.call.do_setup(), 

148 mock.call.get_vfs(constants.EXPECTED_FPG)]) 

149 

150 def test_driver_setup_dhss_success(self): 

151 """Driver do_setup without any errors with dhss=True.""" 

152 

153 self.test_driver_setup_success() 

154 self.assertEqual(constants.EXPECTED_FPG_MAP, self.driver.fpgs) 

155 

156 def test_driver_setup_no_dhss_success(self): 

157 """Driver do_setup without any errors with dhss=False.""" 

158 

159 self.conf.driver_handles_share_servers = False 

160 self.test_driver_setup_success() 

161 self.assertEqual(constants.EXPECTED_FPG_MAP, self.driver.fpgs) 

162 

163 def test_driver_setup_no_dhss_multi_getvfs_success(self): 

164 """Driver do_setup when dhss=False, getvfs returns multiple IPs.""" 

165 

166 self.conf.driver_handles_share_servers = False 

167 self.test_driver_setup_success( 

168 get_vfs_ret_val=constants.EXPECTED_GET_VFS_MULTIPLES) 

169 self.assertEqual(constants.EXPECTED_FPG_MAP, 

170 self.driver.fpgs) 

171 

172 def test_driver_setup_success_no_dhss_no_conf_ss_ip(self): 

173 """test driver's do_setup() 

174 

175 Driver do_setup with dhss=False, share server ip not set in config file 

176 but discoverable at 3par array 

177 """ 

178 

179 self.conf.driver_handles_share_servers = False 

180 # ss ip not provided in conf 

181 original_fpg = deepcopy(self.conf.hpe3par_fpg) 

182 self.conf.hpe3par_fpg[0][constants.EXPECTED_FPG] = [] 

183 

184 self.test_driver_setup_success() 

185 

186 self.assertEqual(constants.EXPECTED_FPG_MAP, self.driver.fpgs) 

187 constants.EXPECTED_FPG_CONF = original_fpg 

188 

189 def test_driver_setup_failure_no_dhss_no_conf_ss_ip(self): 

190 """Configured IP address is required for dhss=False.""" 

191 

192 self.conf.driver_handles_share_servers = False 

193 # ss ip not provided in conf 

194 fpg_without_ss_ip = deepcopy(self.conf.hpe3par_fpg) 

195 self.conf.hpe3par_fpg[0][constants.EXPECTED_FPG] = [] 

196 # ss ip not configured on array 

197 vfs_without_ss_ip = deepcopy(constants.EXPECTED_GET_VFS) 

198 vfs_without_ss_ip['vfsip']['address'] = [] 

199 self.mock_mediator.get_vfs.return_value = vfs_without_ss_ip 

200 

201 self.assertRaises(exception.HPE3ParInvalid, 

202 self.driver.do_setup, None) 

203 constants.EXPECTED_FPG_CONF = fpg_without_ss_ip 

204 

205 def test_driver_setup_mediator_error(self): 

206 """Driver do_setup when the mediator setup fails.""" 

207 

208 self.mock_mediator.do_setup.side_effect = ( 

209 exception.ShareBackendException('fail')) 

210 

211 self.assertRaises(exception.ShareBackendException, 

212 self.driver.do_setup, None) 

213 

214 conf = self.conf 

215 self.mock_mediator_constructor.assert_has_calls([ 

216 mock.call(hpe3par_san_ssh_port=conf.hpe3par_san_ssh_port, 

217 hpe3par_san_password=conf.hpe3par_san_password, 

218 hpe3par_username=conf.hpe3par_username, 

219 hpe3par_san_login=conf.hpe3par_san_login, 

220 hpe3par_debug=conf.hpe3par_debug, 

221 hpe3par_api_url=conf.hpe3par_api_url, 

222 hpe3par_password=conf.hpe3par_password, 

223 hpe3par_san_ip=conf.hpe3par_san_ip, 

224 hpe3par_fstore_per_share=conf.hpe3par_fstore_per_share, 

225 hpe3par_require_cifs_ip=conf.hpe3par_require_cifs_ip, 

226 hpe3par_cifs_admin_access_username=( 

227 conf.hpe3par_cifs_admin_access_username), 

228 hpe3par_cifs_admin_access_password=( 

229 conf.hpe3par_cifs_admin_access_password), 

230 hpe3par_cifs_admin_access_domain=( 

231 conf.hpe3par_cifs_admin_access_domain), 

232 hpe3par_share_mount_path=conf.hpe3par_share_mount_path, 

233 my_ip=self.conf.my_ip, 

234 ssh_conn_timeout=conf.ssh_conn_timeout)]) 

235 

236 self.mock_mediator.assert_has_calls([mock.call.do_setup()]) 

237 

238 def test_driver_setup_with_vfs_error(self): 

239 """Driver do_setup when the get_vfs fails.""" 

240 

241 self.mock_mediator.get_vfs.side_effect = ( 

242 exception.ShareBackendException('fail')) 

243 

244 self.assertRaises(exception.ShareBackendException, 

245 self.driver.do_setup, None) 

246 

247 conf = self.conf 

248 self.mock_mediator_constructor.assert_has_calls([ 

249 mock.call(hpe3par_san_ssh_port=conf.hpe3par_san_ssh_port, 

250 hpe3par_san_password=conf.hpe3par_san_password, 

251 hpe3par_username=conf.hpe3par_username, 

252 hpe3par_san_login=conf.hpe3par_san_login, 

253 hpe3par_debug=conf.hpe3par_debug, 

254 hpe3par_api_url=conf.hpe3par_api_url, 

255 hpe3par_password=conf.hpe3par_password, 

256 hpe3par_san_ip=conf.hpe3par_san_ip, 

257 hpe3par_fstore_per_share=conf.hpe3par_fstore_per_share, 

258 hpe3par_require_cifs_ip=conf.hpe3par_require_cifs_ip, 

259 hpe3par_cifs_admin_access_username=( 

260 conf.hpe3par_cifs_admin_access_username), 

261 hpe3par_cifs_admin_access_password=( 

262 conf.hpe3par_cifs_admin_access_password), 

263 hpe3par_cifs_admin_access_domain=( 

264 conf.hpe3par_cifs_admin_access_domain), 

265 hpe3par_share_mount_path=conf.hpe3par_share_mount_path, 

266 my_ip=self.conf.my_ip, 

267 ssh_conn_timeout=conf.ssh_conn_timeout)]) 

268 

269 self.mock_mediator.assert_has_calls([ 

270 mock.call.do_setup(), 

271 mock.call.get_vfs(constants.EXPECTED_FPG)]) 

272 

273 def test_driver_setup_conf_ips_validation_fails(self): 

274 """Driver do_setup when the _validate_pool_ips fails.""" 

275 

276 self.conf.driver_handles_share_servers = False 

277 vfs_with_ss_ip = deepcopy(constants.EXPECTED_GET_VFS) 

278 vfs_with_ss_ip['vfsip']['address'] = ['10.100.100.100'] 

279 self.mock_mediator.get_vfs.return_value = vfs_with_ss_ip 

280 self.assertRaises(exception.HPE3ParInvalid, 

281 self.driver.do_setup, None) 

282 

283 conf = self.conf 

284 self.mock_mediator_constructor.assert_has_calls([ 

285 mock.call(hpe3par_san_ssh_port=conf.hpe3par_san_ssh_port, 

286 hpe3par_san_password=conf.hpe3par_san_password, 

287 hpe3par_username=conf.hpe3par_username, 

288 hpe3par_san_login=conf.hpe3par_san_login, 

289 hpe3par_debug=conf.hpe3par_debug, 

290 hpe3par_api_url=conf.hpe3par_api_url, 

291 hpe3par_password=conf.hpe3par_password, 

292 hpe3par_san_ip=conf.hpe3par_san_ip, 

293 hpe3par_fstore_per_share=conf.hpe3par_fstore_per_share, 

294 hpe3par_require_cifs_ip=conf.hpe3par_require_cifs_ip, 

295 hpe3par_cifs_admin_access_username=( 

296 conf.hpe3par_cifs_admin_access_username), 

297 hpe3par_cifs_admin_access_password=( 

298 conf.hpe3par_cifs_admin_access_password), 

299 hpe3par_cifs_admin_access_domain=( 

300 conf.hpe3par_cifs_admin_access_domain), 

301 hpe3par_share_mount_path=conf.hpe3par_share_mount_path, 

302 my_ip=self.conf.my_ip, 

303 ssh_conn_timeout=conf.ssh_conn_timeout)]) 

304 

305 self.mock_mediator.assert_has_calls([ 

306 mock.call.do_setup(), 

307 mock.call.get_vfs(constants.EXPECTED_FPG)]) 

308 

309 def init_driver(self): 

310 """Simple driver setup for re-use with tests that need one.""" 

311 

312 self.driver._hpe3par = self.mock_mediator 

313 self.driver.fpgs = constants.EXPECTED_FPG_MAP 

314 self.mock_object(hpe3pardriver, 'share_types') 

315 get_extra_specs = hpe3pardriver.share_types.get_extra_specs_from_share 

316 get_extra_specs.return_value = constants.EXPECTED_EXTRA_SPECS 

317 

318 def test_driver_check_for_setup_error_success(self): 

319 """check_for_setup_error when things go well.""" 

320 

321 # Generally this is always mocked, but here we reference the class. 

322 hpe3parmediator.HPE3ParMediator = self.real_hpe_3par_mediator 

323 

324 self.mock_object(hpe3pardriver, 'LOG') 

325 self.init_driver() 

326 self.driver.check_for_setup_error() 

327 expected_calls = [ 

328 mock.call.debug('HPE3ParShareDriver SHA1: %s', mock.ANY), 

329 mock.call.debug('HPE3ParMediator SHA1: %s', mock.ANY) 

330 ] 

331 hpe3pardriver.LOG.assert_has_calls(expected_calls) 

332 

333 def test_driver_check_for_setup_error_exception(self): 

334 """check_for_setup_error catch and log any exceptions.""" 

335 

336 # Since HPE3ParMediator is mocked, we'll hit the except/log. 

337 self.mock_object(hpe3pardriver, 'LOG') 

338 self.init_driver() 

339 self.driver.check_for_setup_error() 

340 expected_calls = [ 

341 mock.call.debug('HPE3ParShareDriver SHA1: %s', mock.ANY), 

342 mock.call.debug('Source code SHA1 not logged due to: %s', mock.ANY) 

343 ] 

344 hpe3pardriver.LOG.assert_has_calls(expected_calls) 

345 

346 @ddt.data(([constants.SHARE_SERVER], constants.SHARE_SERVER), 

347 ([], None),) 

348 @ddt.unpack 

349 def test_choose_share_server_compatible_with_share(self, share_servers, 

350 expected_share_sever): 

351 context = None 

352 share_server = self.driver.choose_share_server_compatible_with_share( 

353 context, 

354 share_servers, 

355 constants.NFS_SHARE_INFO, 

356 None, 

357 None) 

358 

359 self.assertEqual(expected_share_sever, share_server) 

360 

361 def test_choose_share_server_compatible_with_share_with_cg(self): 

362 context = None 

363 cg_ref = {'id': 'dummy'} 

364 self.assertRaises( 

365 exception.InvalidRequest, 

366 self.driver.choose_share_server_compatible_with_share, 

367 context, 

368 [constants.SHARE_SERVER], 

369 constants.NFS_SHARE_INFO, 

370 None, 

371 cg_ref) 

372 

373 def do_create_share(self, protocol, share_type_id, expected_project_id, 

374 expected_share_id, expected_size): 

375 """Re-usable code for create share.""" 

376 context = None 

377 

378 share = { 

379 'display_name': constants.EXPECTED_SHARE_NAME, 

380 'host': constants.EXPECTED_HOST, 

381 'project_id': expected_project_id, 

382 'id': expected_share_id, 

383 'share_proto': protocol, 

384 'share_type_id': share_type_id, 

385 'size': expected_size, 

386 } 

387 location = self.driver.create_share(context, share, 

388 constants.SHARE_SERVER) 

389 return location 

390 

391 def do_create_share_from_snapshot(self, 

392 protocol, 

393 share_type_id, 

394 snapshot_instance, 

395 expected_share_id, 

396 expected_size): 

397 """Re-usable code for create share from snapshot.""" 

398 context = None 

399 share = { 

400 'project_id': constants.EXPECTED_PROJECT_ID, 

401 'display_name': constants.EXPECTED_SHARE_NAME, 

402 'host': constants.EXPECTED_HOST, 

403 'id': expected_share_id, 

404 'share_proto': protocol, 

405 'share_type_id': share_type_id, 

406 'size': expected_size, 

407 } 

408 location = self.driver.create_share_from_snapshot( 

409 context, 

410 share, 

411 snapshot_instance, 

412 constants.SHARE_SERVER) 

413 return location 

414 

415 @ddt.data((constants.UNEXPECTED_HOST, exception.InvalidHost), 

416 (constants.HOST_WITHOUT_POOL_1, exception.InvalidHost), 

417 (constants.HOST_WITHOUT_POOL_2, exception.InvalidHost)) 

418 @ddt.unpack 

419 def test_driver_create_share_fails_get_pool_location(self, host, 

420 expected_exception): 

421 """get_pool_location fails to extract pool name from host""" 

422 self.init_driver() 

423 context = None 

424 share_server = None 

425 share = { 

426 'display_name': constants.EXPECTED_SHARE_NAME, 

427 'host': host, 

428 'project_id': constants.EXPECTED_PROJECT_ID, 

429 'id': constants.EXPECTED_SHARE_ID, 

430 'share_proto': constants.CIFS, 

431 'share_type_id': constants.SHARE_TYPE_ID, 

432 'size': constants.EXPECTED_SIZE_2, 

433 } 

434 self.assertRaises(expected_exception, 

435 self.driver.create_share, 

436 context, share, share_server) 

437 

438 def test_driver_create_cifs_share(self): 

439 self.init_driver() 

440 

441 expected_location = '\\\\%s\\%s' % (constants.EXPECTED_IP_10203040, 

442 constants.EXPECTED_SHARE_NAME) 

443 

444 self.mock_mediator.create_share.return_value = ( 

445 constants.EXPECTED_SHARE_NAME) 

446 

447 hpe3parmediator.HPE3ParMediator = self.real_hpe_3par_mediator 

448 

449 location = self.do_create_share(constants.CIFS, 

450 constants.SHARE_TYPE_ID, 

451 constants.EXPECTED_PROJECT_ID, 

452 constants.EXPECTED_SHARE_ID, 

453 constants.EXPECTED_SIZE_2) 

454 

455 self.assertIn(expected_location, location) 

456 expected_calls = [mock.call.create_share( 

457 constants.EXPECTED_PROJECT_ID, 

458 constants.EXPECTED_SHARE_ID, 

459 constants.CIFS, 

460 constants.EXPECTED_EXTRA_SPECS, 

461 constants.EXPECTED_FPG, 

462 constants.EXPECTED_VFS, 

463 comment=mock.ANY, 

464 size=constants.EXPECTED_SIZE_2)] 

465 self.mock_mediator.assert_has_calls(expected_calls) 

466 

467 def test_driver_create_nfs_share(self): 

468 self.init_driver() 

469 

470 expected_location = ':'.join((constants.EXPECTED_IP_10203040, 

471 constants.EXPECTED_SHARE_PATH)) 

472 

473 self.mock_mediator.create_share.return_value = ( 

474 constants.EXPECTED_SHARE_PATH) 

475 hpe3parmediator.HPE3ParMediator = self.real_hpe_3par_mediator 

476 

477 location = self.do_create_share(constants.NFS, 

478 constants.SHARE_TYPE_ID, 

479 constants.EXPECTED_PROJECT_ID, 

480 constants.EXPECTED_SHARE_ID, 

481 constants.EXPECTED_SIZE_1) 

482 

483 self.assertIn(expected_location, location) 

484 expected_calls = [ 

485 mock.call.create_share(constants.EXPECTED_PROJECT_ID, 

486 constants.EXPECTED_SHARE_ID, 

487 constants.NFS, 

488 constants.EXPECTED_EXTRA_SPECS, 

489 constants.EXPECTED_FPG, 

490 constants.EXPECTED_VFS, 

491 comment=mock.ANY, 

492 size=constants.EXPECTED_SIZE_1)] 

493 

494 self.mock_mediator.assert_has_calls(expected_calls) 

495 

496 def test_driver_create_cifs_share_from_snapshot(self): 

497 self.init_driver() 

498 

499 expected_location = '\\\\%s\\%s' % (constants.EXPECTED_IP_10203040, 

500 constants.EXPECTED_SHARE_NAME) 

501 

502 self.mock_mediator.create_share_from_snapshot.return_value = ( 

503 constants.EXPECTED_SHARE_NAME) 

504 hpe3parmediator.HPE3ParMediator = self.real_hpe_3par_mediator 

505 

506 snapshot_instance = constants.SNAPSHOT_INSTANCE.copy() 

507 snapshot_instance['protocol'] = constants.CIFS 

508 

509 location = self.do_create_share_from_snapshot( 

510 constants.CIFS, 

511 constants.SHARE_TYPE_ID, 

512 snapshot_instance, 

513 constants.EXPECTED_SHARE_ID, 

514 constants.EXPECTED_SIZE_2) 

515 

516 self.assertIn(expected_location, location) 

517 expected_calls = [ 

518 mock.call.create_share_from_snapshot( 

519 constants.EXPECTED_SHARE_ID, 

520 constants.CIFS, 

521 constants.EXPECTED_EXTRA_SPECS, 

522 constants.EXPECTED_FSTORE, 

523 constants.EXPECTED_SHARE_ID, 

524 constants.EXPECTED_SNAP_ID, 

525 constants.EXPECTED_FPG, 

526 constants.EXPECTED_VFS, 

527 [constants.EXPECTED_IP_10203040], 

528 comment=mock.ANY, 

529 size=constants.EXPECTED_SIZE_2), 

530 ] 

531 self.mock_mediator.assert_has_calls(expected_calls) 

532 

533 def test_driver_create_nfs_share_from_snapshot(self): 

534 self.init_driver() 

535 

536 expected_location = ':'.join((constants.EXPECTED_IP_10203040, 

537 constants.EXPECTED_SHARE_PATH)) 

538 

539 self.mock_mediator.create_share_from_snapshot.return_value = ( 

540 constants.EXPECTED_SHARE_PATH) 

541 hpe3parmediator.HPE3ParMediator = self.real_hpe_3par_mediator 

542 

543 location = self.do_create_share_from_snapshot( 

544 constants.NFS, 

545 constants.SHARE_TYPE_ID, 

546 constants.SNAPSHOT_INSTANCE, 

547 constants.EXPECTED_SHARE_ID, 

548 constants.EXPECTED_SIZE_1) 

549 

550 self.assertIn(expected_location, location) 

551 expected_calls = [ 

552 mock.call.create_share_from_snapshot( 

553 constants.EXPECTED_SHARE_ID, 

554 constants.NFS, 

555 constants.EXPECTED_EXTRA_SPECS, 

556 constants.EXPECTED_PROJECT_ID, 

557 constants.EXPECTED_SHARE_ID, 

558 constants.EXPECTED_SNAP_ID, 

559 constants.EXPECTED_FPG, 

560 constants.EXPECTED_VFS, 

561 [constants.EXPECTED_IP_10203040], 

562 comment=mock.ANY, 

563 size=constants.EXPECTED_SIZE_1), 

564 ] 

565 

566 self.mock_mediator.assert_has_calls(expected_calls) 

567 

568 def test_driver_delete_share(self): 

569 self.init_driver() 

570 

571 context = None 

572 share_server = None 

573 share = { 

574 'project_id': constants.EXPECTED_PROJECT_ID, 

575 'id': constants.EXPECTED_SHARE_ID, 

576 'share_proto': constants.CIFS, 

577 'size': constants.EXPECTED_SIZE_1, 

578 'host': constants.EXPECTED_HOST 

579 } 

580 

581 self.driver.delete_share(context, share, share_server) 

582 

583 expected_calls = [ 

584 mock.call.delete_share(constants.EXPECTED_PROJECT_ID, 

585 constants.EXPECTED_SHARE_ID, 

586 constants.EXPECTED_SIZE_1, 

587 constants.CIFS, 

588 constants.EXPECTED_FPG, 

589 constants.EXPECTED_VFS, 

590 constants.EXPECTED_IP_10203040)] 

591 

592 self.mock_mediator.assert_has_calls(expected_calls) 

593 

594 def test_driver_create_snapshot(self): 

595 self.init_driver() 

596 

597 context = None 

598 share_server = None 

599 self.driver.create_snapshot(context, 

600 constants.SNAPSHOT_INFO, 

601 share_server) 

602 

603 expected_calls = [ 

604 mock.call.create_snapshot(constants.EXPECTED_PROJECT_ID, 

605 constants.EXPECTED_SHARE_ID, 

606 constants.NFS, 

607 constants.EXPECTED_SNAP_ID, 

608 constants.EXPECTED_FPG, 

609 constants.EXPECTED_VFS)] 

610 self.mock_mediator.assert_has_calls(expected_calls) 

611 

612 def test_driver_delete_snapshot(self): 

613 self.init_driver() 

614 

615 context = None 

616 share_server = None 

617 self.driver.delete_snapshot(context, 

618 constants.SNAPSHOT_INFO, 

619 share_server) 

620 

621 expected_calls = [ 

622 mock.call.delete_snapshot(constants.EXPECTED_PROJECT_ID, 

623 constants.EXPECTED_SHARE_ID, 

624 constants.NFS, 

625 constants.EXPECTED_SNAP_ID, 

626 constants.EXPECTED_FPG, 

627 constants.EXPECTED_VFS) 

628 ] 

629 self.mock_mediator.assert_has_calls(expected_calls) 

630 

631 def test_driver_update_access_add_rule(self): 

632 self.init_driver() 

633 

634 context = None 

635 

636 self.driver.update_access(context, 

637 constants.NFS_SHARE_INFO, 

638 [constants.ACCESS_RULE_NFS], 

639 [constants.ADD_RULE_IP], 

640 [], 

641 constants.SHARE_SERVER) 

642 

643 expected_calls = [ 

644 mock.call.update_access(constants.EXPECTED_PROJECT_ID, 

645 constants.EXPECTED_SHARE_ID, 

646 constants.NFS, 

647 constants.EXPECTED_EXTRA_SPECS, 

648 [constants.ACCESS_RULE_NFS], 

649 [constants.ADD_RULE_IP], 

650 [], 

651 constants.EXPECTED_FPG, 

652 constants.EXPECTED_VFS) 

653 ] 

654 self.mock_mediator.assert_has_calls(expected_calls) 

655 

656 def test_driver_update_access_delete_rule(self): 

657 self.init_driver() 

658 

659 context = None 

660 

661 self.driver.update_access(context, 

662 constants.NFS_SHARE_INFO, 

663 [constants.ACCESS_RULE_NFS], 

664 [], 

665 [constants.DELETE_RULE_IP], 

666 constants.SHARE_SERVER) 

667 

668 expected_calls = [ 

669 mock.call.update_access(constants.EXPECTED_PROJECT_ID, 

670 constants.EXPECTED_SHARE_ID, 

671 constants.NFS, 

672 constants.EXPECTED_EXTRA_SPECS, 

673 [constants.ACCESS_RULE_NFS], 

674 [], 

675 [constants.DELETE_RULE_IP], 

676 constants.EXPECTED_FPG, 

677 constants.EXPECTED_VFS) 

678 ] 

679 self.mock_mediator.assert_has_calls(expected_calls) 

680 

681 def test_driver_extend_share(self): 

682 self.init_driver() 

683 

684 old_size = constants.NFS_SHARE_INFO['size'] 

685 new_size = old_size * 2 

686 

687 share_server = None 

688 self.driver.extend_share(constants.NFS_SHARE_INFO, 

689 new_size, share_server) 

690 

691 self.mock_mediator.resize_share.assert_called_once_with( 

692 constants.EXPECTED_PROJECT_ID, 

693 constants.EXPECTED_SHARE_ID, 

694 constants.NFS, 

695 new_size, 

696 old_size, 

697 constants.EXPECTED_FPG, 

698 constants.EXPECTED_VFS) 

699 

700 def test_driver_shrink_share(self): 

701 self.init_driver() 

702 

703 old_size = constants.NFS_SHARE_INFO['size'] 

704 new_size = old_size / 2 

705 share_server = None 

706 self.driver.shrink_share(constants.NFS_SHARE_INFO, 

707 new_size, share_server) 

708 

709 self.mock_mediator.resize_share.assert_called_once_with( 

710 constants.EXPECTED_PROJECT_ID, 

711 constants.EXPECTED_SHARE_ID, 

712 constants.NFS, 

713 new_size, 

714 old_size, 

715 constants.EXPECTED_FPG, 

716 constants.EXPECTED_VFS) 

717 

718 def test_driver_get_share_stats_not_ready(self): 

719 """Protect against stats update before driver is ready.""" 

720 

721 self.mock_object(hpe3pardriver, 'LOG') 

722 

723 expected_result = { 

724 'driver_handles_share_servers': True, 

725 'qos': False, 

726 'driver_version': self.driver.VERSION, 

727 'free_capacity_gb': 0, 

728 'max_over_subscription_ratio': None, 

729 'reserved_percentage': 0, 

730 'reserved_snapshot_percentage': 0, 

731 'reserved_share_extend_percentage': 0, 

732 'provisioned_capacity_gb': 0, 

733 'share_backend_name': 'HPE_3PAR', 

734 'snapshot_support': True, 

735 'create_share_from_snapshot_support': True, 

736 'revert_to_snapshot_support': False, 

737 'mount_snapshot_support': False, 

738 'share_group_stats': { 

739 'consistent_snapshot_support': None, 

740 }, 

741 'storage_protocol': 'NFS_CIFS', 

742 'thin_provisioning': True, 

743 'total_capacity_gb': 0, 

744 'vendor_name': 'HPE', 

745 'pools': None, 

746 'replication_domain': None, 

747 'filter_function': None, 

748 'goodness_function': None, 

749 'mount_point_name_support': False, 

750 'ipv4_support': True, 

751 'ipv6_support': False, 

752 'max_share_server_size': -1, 

753 'max_shares_per_share_server': -1, 

754 'security_service_update_support': False, 

755 'share_server_multiple_subnet_support': False, 

756 'network_allocation_update_support': False, 

757 'share_replicas_migration_support': False, 

758 'encryption_support': None, 

759 } 

760 

761 result = self.driver.get_share_stats(refresh=True) 

762 self.assertEqual(expected_result, result) 

763 

764 expected_calls = [ 

765 mock.call.info('Skipping capacity and capabilities update. ' 

766 'Setup has not completed.') 

767 ] 

768 hpe3pardriver.LOG.assert_has_calls(expected_calls) 

769 

770 def test_driver_get_share_stats_no_refresh(self): 

771 """Driver does not call mediator when refresh=False.""" 

772 

773 self.init_driver() 

774 self.driver._stats = constants.EXPECTED_STATS 

775 

776 result = self.driver.get_share_stats(refresh=False) 

777 

778 self.assertEqual(constants.EXPECTED_STATS, result) 

779 self.assertEqual([], self.mock_mediator.mock_calls) 

780 

781 def test_driver_get_share_stats_with_refresh(self): 

782 """Driver adds stats from mediator to expected structure.""" 

783 

784 self.init_driver() 

785 expected_free = constants.EXPECTED_SIZE_1 

786 expected_capacity = constants.EXPECTED_SIZE_2 

787 expected_version = self.driver.VERSION 

788 

789 self.mock_mediator.get_fpg_status.return_value = { 

790 'pool_name': constants.EXPECTED_FPG, 

791 'total_capacity_gb': expected_capacity, 

792 'free_capacity_gb': expected_free, 

793 'thin_provisioning': True, 

794 'dedupe': False, 

795 'hpe3par_flash_cache': False, 

796 'hp3par_flash_cache': False, 

797 'reserved_percentage': 0, 

798 'reserved_snapshot_percentage': 0, 

799 'reserved_share_extend_percentage': 0, 

800 'provisioned_capacity_gb': expected_capacity 

801 } 

802 

803 expected_result = { 

804 'share_backend_name': 'HPE_3PAR', 

805 'vendor_name': 'HPE', 

806 'driver_version': expected_version, 

807 'storage_protocol': 'NFS_CIFS', 

808 'driver_handles_share_servers': True, 

809 'total_capacity_gb': 0, 

810 'free_capacity_gb': 0, 

811 'provisioned_capacity_gb': 0, 

812 'reserved_percentage': 0, 

813 'reserved_snapshot_percentage': 0, 

814 'reserved_share_extend_percentage': 0, 

815 'max_over_subscription_ratio': None, 

816 'max_share_server_size': -1, 

817 'max_shares_per_share_server': -1, 

818 'qos': False, 

819 'thin_provisioning': True, 

820 'pools': [{ 

821 'pool_name': constants.EXPECTED_FPG, 

822 'total_capacity_gb': expected_capacity, 

823 'free_capacity_gb': expected_free, 

824 'thin_provisioning': True, 

825 'dedupe': False, 

826 'hpe3par_flash_cache': False, 

827 'hp3par_flash_cache': False, 

828 'reserved_percentage': 0, 

829 'reserved_snapshot_percentage': 0, 

830 'reserved_share_extend_percentage': 0, 

831 'provisioned_capacity_gb': expected_capacity}], 

832 'snapshot_support': True, 

833 'create_share_from_snapshot_support': True, 

834 'revert_to_snapshot_support': False, 

835 'security_service_update_support': False, 

836 'share_server_multiple_subnet_support': False, 

837 'network_allocation_update_support': False, 

838 'mount_snapshot_support': False, 

839 'share_replicas_migration_support': False, 

840 'encryption_support': None, 

841 'share_group_stats': { 

842 'consistent_snapshot_support': None, 

843 }, 

844 'replication_domain': None, 

845 'filter_function': None, 

846 'goodness_function': None, 

847 'mount_point_name_support': False, 

848 'ipv4_support': True, 

849 'ipv6_support': False, 

850 } 

851 

852 result = self.driver.get_share_stats(refresh=True) 

853 self.assertEqual(expected_result, result) 

854 

855 expected_calls = [ 

856 mock.call.get_fpg_status(constants.EXPECTED_FPG) 

857 ] 

858 self.mock_mediator.assert_has_calls(expected_calls) 

859 self.assertTrue(self.mock_mediator.get_fpg_status.called) 

860 

861 def test_driver_get_share_stats_premature(self): 

862 """Driver init stats before init_driver completed.""" 

863 

864 expected_version = self.driver.VERSION 

865 

866 self.mock_mediator.get_fpg_status.return_value = {'not_called': 1} 

867 

868 expected_result = { 

869 'qos': False, 

870 'driver_handles_share_servers': True, 

871 'driver_version': expected_version, 

872 'free_capacity_gb': 0, 

873 'max_over_subscription_ratio': None, 

874 'max_share_server_size': -1, 

875 'max_shares_per_share_server': -1, 

876 'pools': None, 

877 'provisioned_capacity_gb': 0, 

878 'reserved_percentage': 0, 

879 'reserved_snapshot_percentage': 0, 

880 'reserved_share_extend_percentage': 0, 

881 'share_backend_name': 'HPE_3PAR', 

882 'storage_protocol': 'NFS_CIFS', 

883 'thin_provisioning': True, 

884 'total_capacity_gb': 0, 

885 'vendor_name': 'HPE', 

886 'snapshot_support': True, 

887 'create_share_from_snapshot_support': True, 

888 'revert_to_snapshot_support': False, 

889 'security_service_update_support': False, 

890 'share_server_multiple_subnet_support': False, 

891 'network_allocation_update_support': False, 

892 'share_replicas_migration_support': False, 

893 'encryption_support': None, 

894 'mount_snapshot_support': False, 

895 'share_group_stats': { 

896 'consistent_snapshot_support': None, 

897 }, 

898 'replication_domain': None, 

899 'filter_function': None, 

900 'goodness_function': None, 

901 'mount_point_name_support': False, 

902 'ipv4_support': True, 

903 'ipv6_support': False, 

904 } 

905 

906 result = self.driver.get_share_stats(refresh=True) 

907 self.assertEqual(expected_result, result) 

908 self.assertFalse(self.mock_mediator.get_fpg_status.called) 

909 

910 @ddt.data(('test"dquote', 'test_dquote'), 

911 ("test'squote", "test_squote"), 

912 ('test-:;,.punc', 'test-:_punc'), 

913 ('test with spaces ', 'test with spaces '), 

914 ('x' * 300, 'x' * 300)) 

915 @ddt.unpack 

916 def test_build_comment(self, display_name, clean_name): 

917 

918 host = 'test-stack1@backend#pool' 

919 share = { 

920 'host': host, 

921 'display_name': display_name 

922 } 

923 comment = self.driver.build_share_comment(share) 

924 

925 cleaned = { 

926 'host': host, 

927 'clean_name': clean_name 

928 } 

929 

930 expected = ("OpenStack Manila - host=%(host)s " 

931 "orig_name=%(clean_name)s created=" % cleaned)[:254] 

932 

933 self.assertLess(len(comment), 255) 

934 self.assertTrue(comment.startswith(expected)) 

935 

936 # Test for some chars that are not allowed. 

937 # Don't test with same regex as the code uses. 

938 for c in "'\".,;": 

939 self.assertNotIn(c, comment) 

940 

941 def test_get_network_allocations_number(self): 

942 self.assertEqual(1, self.driver.get_network_allocations_number()) 

943 

944 def test_setup_server(self): 

945 """Setup server by creating a new FSIP.""" 

946 

947 self.init_driver() 

948 

949 network_info = [{ 

950 'network_allocations': [ 

951 {'ip_address': constants.EXPECTED_IP_1234}], 

952 'cidr': '/'.join((constants.EXPECTED_IP_1234, 

953 constants.CIDR_PREFIX)), 

954 'network_type': constants.EXPECTED_VLAN_TYPE, 

955 'segmentation_id': constants.EXPECTED_VLAN_TAG, 

956 'server_id': constants.EXPECTED_SERVER_ID, 

957 }] 

958 

959 expected_result = { 

960 'share_server_name': constants.EXPECTED_SERVER_ID, 

961 'share_server_id': constants.EXPECTED_SERVER_ID, 

962 'ip': constants.EXPECTED_IP_1234, 

963 'subnet': constants.EXPECTED_SUBNET, 

964 'vlantag': constants.EXPECTED_VLAN_TAG, 

965 'fpg': constants.EXPECTED_FPG, 

966 'vfs': constants.EXPECTED_VFS, 

967 } 

968 metadata = {'request_host': constants.EXPECTED_HOST} 

969 result = self.driver._setup_server(network_info, metadata) 

970 

971 expected_calls = [ 

972 mock.call.create_fsip(constants.EXPECTED_IP_1234, 

973 constants.EXPECTED_SUBNET, 

974 constants.EXPECTED_VLAN_TAG, 

975 constants.EXPECTED_FPG, 

976 constants.EXPECTED_VFS) 

977 ] 

978 self.mock_mediator.assert_has_calls(expected_calls) 

979 

980 self.assertEqual(expected_result, result) 

981 

982 def test_setup_server_fails_for_unsupported_network_type(self): 

983 """Setup server fails for unsupported network type""" 

984 

985 self.init_driver() 

986 

987 network_info = [{ 

988 'network_allocations': [ 

989 {'ip_address': constants.EXPECTED_IP_1234}], 

990 'cidr': '/'.join((constants.EXPECTED_IP_1234, 

991 constants.CIDR_PREFIX)), 

992 'network_type': constants.EXPECTED_VXLAN_TYPE, 

993 'segmentation_id': constants.EXPECTED_VLAN_TAG, 

994 'server_id': constants.EXPECTED_SERVER_ID, 

995 }] 

996 metadata = {'request_host': constants.EXPECTED_HOST} 

997 

998 self.assertRaises(exception.NetworkBadConfigurationException, 

999 self.driver._setup_server, 

1000 network_info, metadata) 

1001 

1002 def test_setup_server_fails_for_exceed_pool_max_supported_ips(self): 

1003 """Setup server fails when the VFS has reached max supported IPs""" 

1004 

1005 self.init_driver() 

1006 

1007 network_info = [{ 

1008 'network_allocations': [ 

1009 {'ip_address': constants.EXPECTED_IP_1234}], 

1010 'cidr': '/'.join((constants.EXPECTED_IP_1234, 

1011 constants.CIDR_PREFIX)), 

1012 'network_type': constants.EXPECTED_VLAN_TYPE, 

1013 'segmentation_id': constants.EXPECTED_VLAN_TAG, 

1014 'server_id': constants.EXPECTED_SERVER_ID, 

1015 }] 

1016 metadata = {'request_host': constants.EXPECTED_HOST} 

1017 

1018 expected_vfs = self.driver.fpgs[ 

1019 constants.EXPECTED_FPG][constants.EXPECTED_VFS] 

1020 self.driver.fpgs[constants.EXPECTED_FPG][constants.EXPECTED_VFS] = [ 

1021 '10.0.0.1', '10.0.0.2', '10.0.0.3', '10.0.0.4'] 

1022 

1023 self.assertRaises(exception.Invalid, 

1024 self.driver._setup_server, 

1025 network_info, metadata) 

1026 self.driver.fpgs[constants.EXPECTED_FPG][constants.EXPECTED_VFS 

1027 ] = expected_vfs 

1028 

1029 def test_teardown_server(self): 

1030 """Test tear down server""" 

1031 

1032 self.init_driver() 

1033 

1034 server_details = { 

1035 'ip': constants.EXPECTED_IP_10203040, 

1036 'fpg': constants.EXPECTED_FPG, 

1037 'vfs': constants.EXPECTED_VFS, 

1038 } 

1039 

1040 self.driver._teardown_server(server_details) 

1041 

1042 expected_calls = [ 

1043 mock.call.remove_fsip(constants.EXPECTED_IP_10203040, 

1044 constants.EXPECTED_FPG, 

1045 constants.EXPECTED_VFS) 

1046 ] 

1047 self.mock_mediator.assert_has_calls(expected_calls)