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

314 statements  

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

1# Copyright (c) 2014 Red Hat, 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 copy 

17import errno 

18import os 

19from unittest import mock 

20 

21import ddt 

22from oslo_config import cfg 

23 

24from manila import context 

25from manila import exception 

26from manila.share import configuration as config 

27from manila.share.drivers import ganesha 

28from manila import test 

29from manila.tests import fake_share 

30 

31CONF = cfg.CONF 

32 

33 

34fake_basepath = '/fakepath' 

35 

36fake_export_name = 'fakename--fakeaccid' 

37 

38fake_output_template = { 

39 'EXPORT': { 

40 'Export_Id': 101, 

41 'Path': '/fakepath/fakename', 

42 'Pseudo': '/fakepath/fakename--fakeaccid', 

43 'Tag': 'fakeaccid', 

44 'CLIENT': { 

45 'Clients': '10.0.0.1' 

46 }, 

47 'FSAL': 'fakefsal' 

48 } 

49} 

50 

51 

52@ddt.ddt 

53class GaneshaNASHelperTestCase(test.TestCase): 

54 """Tests GaneshaNASHElper.""" 

55 

56 def setUp(self): 

57 super(GaneshaNASHelperTestCase, self).setUp() 

58 

59 CONF.set_default('ganesha_config_path', '/fakedir0/fakeconfig') 

60 CONF.set_default('ganesha_db_path', '/fakedir1/fake.db') 

61 CONF.set_default('ganesha_export_dir', '/fakedir0/export.d') 

62 CONF.set_default('ganesha_export_template_dir', 

63 '/fakedir2/faketempl.d') 

64 CONF.set_default('ganesha_service_name', 'ganesha.fakeservice') 

65 self._context = context.get_admin_context() 

66 self._execute = mock.Mock(return_value=('', '')) 

67 self.fake_conf = config.Configuration(None) 

68 self.fake_conf_dir_path = '/fakedir0/exports.d' 

69 self._helper = ganesha.GaneshaNASHelper( 

70 self._execute, self.fake_conf, tag='faketag') 

71 self._helper.ganesha = mock.Mock() 

72 self._helper.export_template = {'key': 'value'} 

73 self.share = fake_share.fake_share() 

74 self.access = fake_share.fake_access() 

75 

76 def test_load_conf_dir(self): 

77 fake_template1 = {'key': 'value1'} 

78 fake_template2 = {'key': 'value2'} 

79 fake_ls_dir = ['fakefile0.conf', 'fakefile1.json', 'fakefile2.txt'] 

80 mock_ganesha_utils_patch = mock.Mock() 

81 

82 def fake_patch_run(tmpl1, tmpl2): 

83 mock_ganesha_utils_patch( 

84 copy.deepcopy(tmpl1), copy.deepcopy(tmpl2)) 

85 tmpl1.update(tmpl2) 

86 

87 self.mock_object(ganesha.os, 'listdir', 

88 mock.Mock(return_value=fake_ls_dir)) 

89 self.mock_object(ganesha.LOG, 'info') 

90 self.mock_object(ganesha.ganesha_manager, 'parseconf', 

91 mock.Mock(side_effect=[fake_template1, 

92 fake_template2])) 

93 self.mock_object(ganesha.ganesha_utils, 'patch', 

94 mock.Mock(side_effect=fake_patch_run)) 

95 with mock.patch('builtins.open', 

96 mock.mock_open()) as mockopen: 

97 mockopen().read.side_effect = ['fakeconf0', 'fakeconf1'] 

98 ret = self._helper._load_conf_dir(self.fake_conf_dir_path) 

99 ganesha.os.listdir.assert_called_once_with( 

100 self.fake_conf_dir_path) 

101 ganesha.LOG.info.assert_called_once_with( 

102 mock.ANY, self.fake_conf_dir_path) 

103 mockopen.assert_has_calls([ 

104 mock.call('/fakedir0/exports.d/fakefile0.conf'), 

105 mock.call('/fakedir0/exports.d/fakefile1.json')], 

106 any_order=True) 

107 ganesha.ganesha_manager.parseconf.assert_has_calls([ 

108 mock.call('fakeconf0'), mock.call('fakeconf1')]) 

109 mock_ganesha_utils_patch.assert_has_calls([ 

110 mock.call({}, fake_template1), 

111 mock.call(fake_template1, fake_template2)]) 

112 self.assertEqual(fake_template2, ret) 

113 

114 def test_load_conf_dir_no_conf_dir_must_exist_false(self): 

115 self.mock_object( 

116 ganesha.os, 'listdir', 

117 mock.Mock(side_effect=OSError(errno.ENOENT, 

118 os.strerror(errno.ENOENT)))) 

119 self.mock_object(ganesha.LOG, 'info') 

120 self.mock_object(ganesha.ganesha_manager, 'parseconf') 

121 self.mock_object(ganesha.ganesha_utils, 'patch') 

122 with mock.patch('builtins.open', 

123 mock.mock_open(read_data='fakeconf')) as mockopen: 

124 ret = self._helper._load_conf_dir(self.fake_conf_dir_path, 

125 must_exist=False) 

126 ganesha.os.listdir.assert_called_once_with( 

127 self.fake_conf_dir_path) 

128 ganesha.LOG.info.assert_called_once_with( 

129 mock.ANY, self.fake_conf_dir_path) 

130 self.assertFalse(mockopen.called) 

131 self.assertFalse(ganesha.ganesha_manager.parseconf.called) 

132 self.assertFalse(ganesha.ganesha_utils.patch.called) 

133 self.assertEqual({}, ret) 

134 

135 def test_load_conf_dir_error_no_conf_dir_must_exist_true(self): 

136 self.mock_object( 

137 ganesha.os, 'listdir', 

138 mock.Mock(side_effect=OSError(errno.ENOENT, 

139 os.strerror(errno.ENOENT)))) 

140 self.assertRaises(OSError, self._helper._load_conf_dir, 

141 self.fake_conf_dir_path) 

142 ganesha.os.listdir.assert_called_once_with(self.fake_conf_dir_path) 

143 

144 def test_load_conf_dir_error_conf_dir_present_must_exist_false(self): 

145 self.mock_object( 

146 ganesha.os, 'listdir', 

147 mock.Mock(side_effect=OSError(errno.EACCES, 

148 os.strerror(errno.EACCES)))) 

149 self.assertRaises(OSError, self._helper._load_conf_dir, 

150 self.fake_conf_dir_path, must_exist=False) 

151 ganesha.os.listdir.assert_called_once_with(self.fake_conf_dir_path) 

152 

153 def test_load_conf_dir_error(self): 

154 self.mock_object( 

155 ganesha.os, 'listdir', 

156 mock.Mock(side_effect=RuntimeError('fake error'))) 

157 self.assertRaises(RuntimeError, self._helper._load_conf_dir, 

158 self.fake_conf_dir_path) 

159 ganesha.os.listdir.assert_called_once_with(self.fake_conf_dir_path) 

160 

161 def test_init_helper(self): 

162 mock_template = mock.Mock() 

163 mock_ganesha_manager = mock.Mock() 

164 self.mock_object(ganesha.ganesha_manager, 'GaneshaManager', 

165 mock.Mock(return_value=mock_ganesha_manager)) 

166 self.mock_object(self._helper, '_load_conf_dir', 

167 mock.Mock(return_value=mock_template)) 

168 self.mock_object(self._helper, '_default_config_hook') 

169 ret = self._helper.init_helper() 

170 ganesha.ganesha_manager.GaneshaManager.assert_called_once_with( 

171 self._execute, 'faketag', 

172 ganesha_config_path='/fakedir0/fakeconfig', 

173 ganesha_export_dir='/fakedir0/export.d', 

174 ganesha_db_path='/fakedir1/fake.db', 

175 ganesha_service_name='ganesha.fakeservice') 

176 self._helper._load_conf_dir.assert_called_once_with( 

177 '/fakedir2/faketempl.d', must_exist=False) 

178 self.assertFalse(self._helper._default_config_hook.called) 

179 self.assertEqual(mock_ganesha_manager, self._helper.ganesha) 

180 self.assertEqual(mock_template, self._helper.export_template) 

181 self.assertIsNone(ret) 

182 

183 def test_init_helper_conf_dir_empty(self): 

184 mock_template = mock.Mock() 

185 mock_ganesha_manager = mock.Mock() 

186 self.mock_object(ganesha.ganesha_manager, 'GaneshaManager', 

187 mock.Mock(return_value=mock_ganesha_manager)) 

188 self.mock_object(self._helper, '_load_conf_dir', 

189 mock.Mock(return_value={})) 

190 self.mock_object(self._helper, '_default_config_hook', 

191 mock.Mock(return_value=mock_template)) 

192 ret = self._helper.init_helper() 

193 ganesha.ganesha_manager.GaneshaManager.assert_called_once_with( 

194 self._execute, 'faketag', 

195 ganesha_config_path='/fakedir0/fakeconfig', 

196 ganesha_export_dir='/fakedir0/export.d', 

197 ganesha_db_path='/fakedir1/fake.db', 

198 ganesha_service_name='ganesha.fakeservice') 

199 self._helper._load_conf_dir.assert_called_once_with( 

200 '/fakedir2/faketempl.d', must_exist=False) 

201 self._helper._default_config_hook.assert_called_once_with() 

202 self.assertEqual(mock_ganesha_manager, self._helper.ganesha) 

203 self.assertEqual(mock_template, self._helper.export_template) 

204 self.assertIsNone(ret) 

205 

206 def test_default_config_hook(self): 

207 fake_template = {'key': 'value'} 

208 self.mock_object(ganesha.ganesha_utils, 'path_from', 

209 mock.Mock(return_value='/fakedir3/fakeconfdir')) 

210 self.mock_object(self._helper, '_load_conf_dir', 

211 mock.Mock(return_value=fake_template)) 

212 ret = self._helper._default_config_hook() 

213 ganesha.ganesha_utils.path_from.assert_called_once_with( 

214 ganesha.__file__, 'conf') 

215 self._helper._load_conf_dir.assert_called_once_with( 

216 '/fakedir3/fakeconfdir') 

217 self.assertEqual(fake_template, ret) 

218 

219 def test_fsal_hook(self): 

220 ret = self._helper._fsal_hook('/fakepath', self.share, self.access) 

221 self.assertEqual({}, ret) 

222 

223 def test_cleanup_fsal_hook(self): 

224 ret = self._helper._cleanup_fsal_hook('/fakepath', self.share, 

225 self.access) 

226 self.assertIsNone(ret) 

227 

228 def test_allow_access(self): 

229 mock_ganesha_utils_patch = mock.Mock() 

230 

231 def fake_patch_run(tmpl1, tmpl2, tmpl3): 

232 mock_ganesha_utils_patch(copy.deepcopy(tmpl1), tmpl2, tmpl3) 

233 tmpl1.update(tmpl3) 

234 

235 self.mock_object(self._helper.ganesha, 'get_export_id', 

236 mock.Mock(return_value=101)) 

237 self.mock_object(self._helper, '_fsal_hook', 

238 mock.Mock(return_value='fakefsal')) 

239 self.mock_object(ganesha.ganesha_utils, 'patch', 

240 mock.Mock(side_effect=fake_patch_run)) 

241 self.mock_object(ganesha.ganesha_utils, 'validate_access_rule', 

242 mock.Mock(return_value=True)) 

243 ret = self._helper._allow_access(fake_basepath, self.share, 

244 self.access) 

245 self._helper.ganesha.get_export_id.assert_called_once_with() 

246 self._helper._fsal_hook.assert_called_once_with( 

247 fake_basepath, self.share, self.access, sub_name=None) 

248 mock_ganesha_utils_patch.assert_called_once_with( 

249 {}, self._helper.export_template, fake_output_template) 

250 self._helper._fsal_hook.assert_called_once_with( 

251 fake_basepath, self.share, self.access, sub_name=None) 

252 self._helper.ganesha.add_export.assert_called_once_with( 

253 fake_export_name, fake_output_template) 

254 self.assertIsNone(ret) 

255 

256 def test_allow_access_error_invalid_share(self): 

257 access = fake_share.fake_access(access_type='notip') 

258 self.assertRaises(exception.InvalidShareAccess, 

259 self._helper._allow_access, '/fakepath', 

260 self.share, access) 

261 

262 def test_deny_access(self): 

263 ret = self._helper._deny_access('/fakepath', self.share, self.access) 

264 self._helper.ganesha.remove_export.assert_called_once_with( 

265 'fakename--fakeaccid') 

266 self.assertIsNone(ret) 

267 

268 def test_update_access_for_allow(self): 

269 self.mock_object(self._helper, '_allow_access') 

270 self.mock_object(self._helper, '_deny_access') 

271 

272 self._helper.update_access( 

273 self._context, self.share, access_rules=[self.access], 

274 add_rules=[self.access], delete_rules=[], update_rules=[]) 

275 

276 self._helper._allow_access.assert_called_once_with( 

277 '/', self.share, self.access) 

278 

279 self.assertFalse(self._helper._deny_access.called) 

280 self.assertFalse(self._helper.ganesha.reset_exports.called) 

281 self.assertFalse(self._helper.ganesha.restart_service.called) 

282 

283 def test_update_access_for_deny(self): 

284 self.mock_object(self._helper, '_allow_access') 

285 self.mock_object(self._helper, '_deny_access') 

286 

287 self._helper.update_access( 

288 self._context, self.share, access_rules=[], 

289 add_rules=[], delete_rules=[self.access], update_rules=[]) 

290 

291 self._helper._deny_access.assert_called_once_with( 

292 '/', self.share, self.access) 

293 

294 self.assertFalse(self._helper._allow_access.called) 

295 self.assertFalse(self._helper.ganesha.reset_exports.called) 

296 self.assertFalse(self._helper.ganesha.restart_service.called) 

297 

298 def test_update_access_recovery(self): 

299 self.mock_object(self._helper, '_allow_access') 

300 self.mock_object(self._helper, '_deny_access') 

301 

302 self._helper.update_access( 

303 self._context, self.share, access_rules=[self.access], 

304 add_rules=[], delete_rules=[], update_rules=[]) 

305 

306 self._helper._allow_access.assert_called_once_with( 

307 '/', self.share, self.access) 

308 

309 self.assertFalse(self._helper._deny_access.called) 

310 self.assertTrue(self._helper.ganesha.reset_exports.called) 

311 self.assertTrue(self._helper.ganesha.restart_service.called) 

312 

313 def test_update_access_invalid_share_access_type(self): 

314 bad_rule = fake_share.fake_access(access_type='notip', id='fakeid') 

315 expected = {'fakeid': {'state': 'error'}} 

316 

317 result = self._helper.update_access(self._context, self.share, 

318 access_rules=[bad_rule], 

319 add_rules=[], delete_rules=[], 

320 update_rules=[]) 

321 

322 self.assertEqual(expected, result) 

323 

324 def test_update_access_invalid_share_access_level(self): 

325 bad_rule = fake_share.fake_access(access_level='RO', id='fakeid') 

326 expected = {'fakeid': {'state': 'error'}} 

327 

328 result = self._helper.update_access(self._context, self.share, 

329 access_rules=[bad_rule], 

330 add_rules=[], delete_rules=[], 

331 update_rules=[]) 

332 

333 self.assertEqual(expected, result) 

334 

335 

336@ddt.ddt 

337class GaneshaNASHelper2TestCase(test.TestCase): 

338 """Tests GaneshaNASHelper2.""" 

339 

340 def setUp(self): 

341 super(GaneshaNASHelper2TestCase, self).setUp() 

342 

343 CONF.set_default('ganesha_config_path', '/fakedir0/fakeconfig') 

344 CONF.set_default('ganesha_db_path', '/fakedir1/fake.db') 

345 CONF.set_default('ganesha_export_dir', '/fakedir0/export.d') 

346 CONF.set_default('ganesha_export_template_dir', 

347 '/fakedir2/faketempl.d') 

348 CONF.set_default('ganesha_service_name', 'ganesha.fakeservice') 

349 CONF.set_default('ganesha_rados_store_enable', True) 

350 CONF.set_default('ganesha_rados_store_pool_name', 'ceph_pool') 

351 CONF.set_default('ganesha_rados_export_index', 'fake_index') 

352 CONF.set_default('ganesha_rados_export_counter', 'fake_counter') 

353 

354 self._context = context.get_admin_context() 

355 self._execute = mock.Mock(return_value=('', '')) 

356 self.rados_client = mock.Mock() 

357 self.fake_conf = config.Configuration(None) 

358 self.fake_conf_dir_path = '/fakedir0/exports.d' 

359 self._helper = ganesha.GaneshaNASHelper2( 

360 self._execute, self.fake_conf, tag='faketag', 

361 rados_client=self.rados_client) 

362 self._helper.ganesha = mock.Mock() 

363 self._helper.export_template = {} 

364 self.share = fake_share.fake_share() 

365 self.rule1 = fake_share.fake_access(access_level='ro') 

366 self.rule2 = fake_share.fake_access(access_level='rw', 

367 access_to='10.0.0.2') 

368 

369 @ddt.data(False, True) 

370 def test_init_helper_with_rados_store(self, rados_store_enable): 

371 CONF.set_default('ganesha_rados_store_enable', rados_store_enable) 

372 mock_template = mock.Mock() 

373 mock_ganesha_manager = mock.Mock() 

374 self.mock_object(ganesha.ganesha_manager, 'GaneshaManager', 

375 mock.Mock(return_value=mock_ganesha_manager)) 

376 self.mock_object(self._helper, '_load_conf_dir', 

377 mock.Mock(return_value={})) 

378 self.mock_object(self._helper, '_default_config_hook', 

379 mock.Mock(return_value=mock_template)) 

380 

381 ret = self._helper.init_helper() 

382 

383 if rados_store_enable: 

384 kwargs = { 

385 'ganesha_config_path': '/fakedir0/fakeconfig', 

386 'ganesha_export_dir': '/fakedir0/export.d', 

387 'ganesha_service_name': 'ganesha.fakeservice', 

388 'ganesha_rados_store_enable': True, 

389 'ganesha_rados_store_pool_name': 'ceph_pool', 

390 'ganesha_rados_export_index': 'fake_index', 

391 'ganesha_rados_export_counter': 'fake_counter', 

392 'rados_client': self.rados_client 

393 } 

394 else: 

395 kwargs = { 

396 'ganesha_config_path': '/fakedir0/fakeconfig', 

397 'ganesha_export_dir': '/fakedir0/export.d', 

398 'ganesha_service_name': 'ganesha.fakeservice', 

399 'ganesha_db_path': '/fakedir1/fake.db' 

400 } 

401 ganesha.ganesha_manager.GaneshaManager.assert_called_once_with( 

402 self._execute, '<no name>', **kwargs) 

403 self._helper._load_conf_dir.assert_called_once_with( 

404 '/fakedir2/faketempl.d', must_exist=False) 

405 self.assertEqual(mock_ganesha_manager, self._helper.ganesha) 

406 self._helper._default_config_hook.assert_called_once_with() 

407 self.assertEqual(mock_template, self._helper.export_template) 

408 self.assertIsNone(ret) 

409 

410 @ddt.data(False, True) 

411 def test_init_helper_conf_dir_empty(self, conf_dir_empty): 

412 mock_template = mock.Mock() 

413 mock_ganesha_manager = mock.Mock() 

414 self.mock_object(ganesha.ganesha_manager, 'GaneshaManager', 

415 mock.Mock(return_value=mock_ganesha_manager)) 

416 if conf_dir_empty: 

417 self.mock_object(self._helper, '_load_conf_dir', 

418 mock.Mock(return_value={})) 

419 else: 

420 self.mock_object(self._helper, '_load_conf_dir', 

421 mock.Mock(return_value=mock_template)) 

422 self.mock_object(self._helper, '_default_config_hook', 

423 mock.Mock(return_value=mock_template)) 

424 

425 ret = self._helper.init_helper() 

426 

427 ganesha.ganesha_manager.GaneshaManager.assert_called_once_with( 

428 self._execute, '<no name>', 

429 ganesha_config_path='/fakedir0/fakeconfig', 

430 ganesha_export_dir='/fakedir0/export.d', 

431 ganesha_service_name='ganesha.fakeservice', 

432 ganesha_rados_store_enable=True, 

433 ganesha_rados_store_pool_name='ceph_pool', 

434 ganesha_rados_export_index='fake_index', 

435 ganesha_rados_export_counter='fake_counter', 

436 rados_client=self.rados_client) 

437 self._helper._load_conf_dir.assert_called_once_with( 

438 '/fakedir2/faketempl.d', must_exist=False) 

439 self.assertEqual(mock_ganesha_manager, self._helper.ganesha) 

440 if conf_dir_empty: 

441 self._helper._default_config_hook.assert_called_once_with() 

442 else: 

443 self.assertFalse(self._helper._default_config_hook.called) 

444 self.assertEqual(mock_template, self._helper.export_template) 

445 self.assertIsNone(ret) 

446 

447 def test_init_helper_with_rados_store_pool_name_not_set(self): 

448 self.mock_object(ganesha.ganesha_manager, 'GaneshaManager') 

449 self.mock_object(self._helper, '_load_conf_dir') 

450 self.mock_object(self._helper, '_default_config_hook') 

451 self._helper.configuration.ganesha_rados_store_pool_name = None 

452 

453 self.assertRaises( 

454 exception.GaneshaException, self._helper.init_helper) 

455 

456 self.assertFalse(ganesha.ganesha_manager.GaneshaManager.called) 

457 self.assertFalse(self._helper._load_conf_dir.called) 

458 self.assertFalse(self._helper._default_config_hook.called) 

459 

460 def test_update_access_add_export(self): 

461 mock_gh = self._helper.ganesha 

462 self.mock_object(mock_gh, 'check_export_exists', 

463 mock.Mock(return_value=False)) 

464 self.mock_object(mock_gh, 'get_export_id', 

465 mock.Mock(return_value=100)) 

466 self.mock_object(self._helper, '_get_export_path', 

467 mock.Mock(return_value='/fakepath')) 

468 self.mock_object(self._helper, '_get_export_pseudo_path', 

469 mock.Mock(return_value='/fakepath')) 

470 self.mock_object(self._helper, '_fsal_hook', 

471 mock.Mock(return_value={'Name': 'fake'})) 

472 self.mock_object(ganesha.ganesha_utils, 'validate_access_rule', 

473 mock.Mock(return_value=True)) 

474 result_confdict = { 

475 'EXPORT': { 

476 'Export_Id': 100, 

477 'Path': '/fakepath', 

478 'Pseudo': '/fakepath', 

479 'Tag': 'fakename', 

480 'CLIENT': [{ 

481 'Access_Type': 'ro', 

482 'Clients': '10.0.0.1'}], 

483 'FSAL': {'Name': 'fake'} 

484 } 

485 } 

486 

487 self._helper.update_access( 

488 self._context, self.share, access_rules=[self.rule1], 

489 add_rules=[], delete_rules=[], update_rules=[]) 

490 

491 mock_gh.check_export_exists.assert_called_once_with('fakename') 

492 mock_gh.get_export_id.assert_called_once_with() 

493 self._helper._get_export_path.assert_called_once_with( 

494 self.share, sub_name=None) 

495 (self._helper._get_export_pseudo_path.assert_called_once_with( 

496 self.share, sub_name=None)) 

497 self._helper._fsal_hook.assert_called_once_with( 

498 None, self.share, None, sub_name=None) 

499 mock_gh.add_export.assert_called_once_with( 

500 'fakename', result_confdict) 

501 self.assertFalse(mock_gh.update_export.called) 

502 self.assertFalse(mock_gh.remove_export.called) 

503 

504 @ddt.data({'Access_Type': 'ro', 'Clients': '10.0.0.1'}, 

505 [{'Access_Type': 'ro', 'Clients': '10.0.0.1'}]) 

506 def test_update_access_update_export(self, client): 

507 mock_gh = self._helper.ganesha 

508 self.mock_object(mock_gh, 'check_export_exists', 

509 mock.Mock(return_value=True)) 

510 self.mock_object( 

511 mock_gh, '_read_export', 

512 mock.Mock(return_value={'EXPORT': {'CLIENT': client}}) 

513 ) 

514 self.mock_object(ganesha.ganesha_utils, 'validate_access_rule', 

515 mock.Mock(return_value=True)) 

516 result_confdict = { 

517 'EXPORT': { 

518 'CLIENT': [ 

519 {'Access_Type': 'ro', 'Clients': '10.0.0.1'}, 

520 {'Access_Type': 'rw', 'Clients': '10.0.0.2'}] 

521 } 

522 } 

523 

524 self._helper.update_access( 

525 self._context, self.share, access_rules=[self.rule1, self.rule2], 

526 add_rules=[self.rule2], delete_rules=[], update_rules=[]) 

527 

528 mock_gh.check_export_exists.assert_called_once_with('fakename') 

529 mock_gh.update_export.assert_called_once_with('fakename', 

530 result_confdict) 

531 self.assertFalse(mock_gh.add_export.called) 

532 self.assertFalse(mock_gh.remove_export.called) 

533 

534 def test_update_access_remove_export(self): 

535 mock_gh = self._helper.ganesha 

536 self.mock_object(mock_gh, 'check_export_exists', 

537 mock.Mock(return_value=True)) 

538 self.mock_object(self._helper, '_cleanup_fsal_hook') 

539 client = {'Access_Type': 'ro', 'Clients': '10.0.0.1'} 

540 self.mock_object( 

541 mock_gh, '_read_export', 

542 mock.Mock(return_value={'EXPORT': {'CLIENT': client}}) 

543 ) 

544 

545 self._helper.update_access( 

546 self._context, self.share, access_rules=[], 

547 add_rules=[], delete_rules=[self.rule1], update_rules=[]) 

548 

549 mock_gh.check_export_exists.assert_called_once_with('fakename') 

550 mock_gh.remove_export.assert_called_once_with('fakename') 

551 self._helper._cleanup_fsal_hook.assert_called_once_with( 

552 None, self.share, None, sub_name=None) 

553 self.assertFalse(mock_gh.add_export.called) 

554 self.assertFalse(mock_gh.update_export.called) 

555 

556 def test_update_access_export_file_already_removed(self): 

557 mock_gh = self._helper.ganesha 

558 self.mock_object(mock_gh, 'check_export_exists', 

559 mock.Mock(return_value=False)) 

560 self.mock_object(ganesha.LOG, 'warning') 

561 self.mock_object(self._helper, '_cleanup_fsal_hook') 

562 

563 self._helper.update_access( 

564 self._context, self.share, access_rules=[], 

565 add_rules=[], delete_rules=[self.rule1], update_rules=[]) 

566 

567 mock_gh.check_export_exists.assert_called_once_with('fakename') 

568 ganesha.LOG.warning.assert_called_once_with(mock.ANY, mock.ANY) 

569 self.assertFalse(mock_gh.add_export.called) 

570 self.assertFalse(mock_gh.update_export.called) 

571 self.assertFalse(mock_gh.remove_export.called) 

572 self.assertFalse(self._helper._cleanup_fsal_hook.called) 

573 

574 def test_update_access_invalid_share_access_type(self): 

575 mock_gh = self._helper.ganesha 

576 self.mock_object(mock_gh, 'check_export_exists', 

577 mock.Mock(return_value=False)) 

578 bad_rule = fake_share.fake_access(access_type='notip', id='fakeid') 

579 expected = {'fakeid': {'state': 'error'}} 

580 

581 result = self._helper.update_access(self._context, self.share, 

582 access_rules=[bad_rule], 

583 add_rules=[], delete_rules=[], 

584 update_rules=[]) 

585 

586 self.assertEqual(expected, result) 

587 

588 def test_update_access_invalid_share_access_level(self): 

589 bad_rule = fake_share.fake_access(access_level='NOT_RO_OR_RW', 

590 id='fakeid') 

591 expected = {'fakeid': {'state': 'error'}} 

592 mock_gh = self._helper.ganesha 

593 self.mock_object(mock_gh, 'check_export_exists', 

594 mock.Mock(return_value=False)) 

595 

596 result = self._helper.update_access(self._context, self.share, 

597 access_rules=[bad_rule], 

598 add_rules=[], delete_rules=[], 

599 update_rules=[]) 

600 

601 self.assertEqual(expected, result)