Coverage for manila/tests/api/v1/test_shares.py: 99%

798 statements  

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

1# Copyright 2012 NetApp 

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 datetime 

18from unittest import mock 

19 

20import ddt 

21from oslo_config import cfg 

22from oslo_serialization import jsonutils 

23import webob 

24 

25from manila.api import common 

26from manila.api.v1 import shares 

27from manila.common import constants 

28from manila import context 

29from manila import db 

30from manila import exception 

31from manila.lock import api as resource_locks 

32from manila import policy 

33from manila.share import api as share_api 

34from manila.share import share_types 

35from manila import test 

36from manila.tests.api.contrib import stubs 

37from manila.tests.api import fakes 

38from manila.tests import db_utils 

39from manila import utils 

40 

41CONF = cfg.CONF 

42 

43 

44@ddt.ddt 

45class ShareAPITest(test.TestCase): 

46 """Share API Test.""" 

47 

48 def setUp(self): 

49 super(ShareAPITest, self).setUp() 

50 self.controller = shares.ShareController() 

51 self.mock_object(db, 'availability_zone_get') 

52 self.mock_object(share_api.API, 'get_all', 

53 stubs.stub_get_all_shares) 

54 self.mock_object(share_api.API, 'get', 

55 stubs.stub_share_get) 

56 self.mock_object(share_api.API, 'update', stubs.stub_share_update) 

57 self.mock_object(share_api.API, 'delete', stubs.stub_share_delete) 

58 self.mock_object(share_api.API, 'get_snapshot', 

59 stubs.stub_snapshot_get) 

60 self.mock_object(share_types, 'get_share_type', 

61 stubs.stub_share_type_get) 

62 self.mock_object( 

63 common, 'validate_public_share_policy', 

64 mock.Mock(side_effect=lambda *args, **kwargs: args[1])) 

65 self.resource_name = self.controller.resource_name 

66 self.mock_policy_check = self.mock_object(policy, 'check_policy') 

67 self.maxDiff = None 

68 self.share = { 

69 "size": 100, 

70 "display_name": "Share Test Name", 

71 "display_description": "Share Test Desc", 

72 "share_proto": "fakeproto", 

73 "availability_zone": "zone1:host1", 

74 "is_public": False, 

75 } 

76 self.create_mock = mock.Mock( 

77 return_value=stubs.stub_share( 

78 '1', 

79 display_name=self.share['display_name'], 

80 display_description=self.share['display_description'], 

81 size=100, 

82 share_proto=self.share['share_proto'].upper(), 

83 availability_zone=self.share['availability_zone']) 

84 ) 

85 self.vt = { 

86 'id': 'fake_volume_type_id', 

87 'name': 'fake_volume_type_name', 

88 'required_extra_specs': { 

89 'driver_handles_share_servers': 'False' 

90 }, 

91 'extra_specs': { 

92 'driver_handles_share_servers': 'False' 

93 } 

94 } 

95 

96 CONF.set_default("default_share_type", None) 

97 

98 def _get_expected_share_detailed_response(self, values=None, admin=False): 

99 share = { 

100 'id': '1', 

101 'name': 'displayname', 

102 'availability_zone': 'fakeaz', 

103 'description': 'displaydesc', 

104 'export_location': 'fake_location', 

105 'export_locations': ['fake_location', 'fake_location2'], 

106 'project_id': 'fakeproject', 

107 'created_at': datetime.datetime(1, 1, 1, 1, 1, 1), 

108 'share_proto': 'FAKEPROTO', 

109 'metadata': {}, 

110 'size': 1, 

111 'snapshot_id': '2', 

112 'share_network_id': None, 

113 'status': 'fakestatus', 

114 'share_type': '1', 

115 'volume_type': '1', 

116 'snapshot_support': True, 

117 'is_public': False, 

118 'links': [ 

119 { 

120 'href': 'http://localhost/share/v1/fake/shares/1', 

121 'rel': 'self' 

122 }, 

123 { 

124 'href': 'http://localhost/share/fake/shares/1', 

125 'rel': 'bookmark' 

126 } 

127 ], 

128 } 

129 if values: 

130 if 'display_name' in values: 

131 values['name'] = values.pop('display_name') 

132 if 'display_description' in values: 

133 values['description'] = values.pop('display_description') 

134 share.update(values) 

135 if share.get('share_proto'): 135 ↛ 137line 135 didn't jump to line 137 because the condition on line 135 was always true

136 share['share_proto'] = share['share_proto'].upper() 

137 if admin: 

138 share['share_server_id'] = 'fake_share_server_id' 

139 share['host'] = 'fakehost' 

140 return {'share': share} 

141 

142 @ddt.data("1.0", "2.0", "2.1") 

143 def test_share_create_original(self, microversion): 

144 self.mock_object(share_api.API, 'create', self.create_mock) 

145 body = {"share": copy.deepcopy(self.share)} 

146 req = fakes.HTTPRequest.blank('/fake/shares', version=microversion) 

147 

148 res_dict = self.controller.create(req, body) 

149 

150 self.mock_policy_check.assert_called_once_with( 

151 req.environ['manila.context'], self.resource_name, 'create') 

152 expected = self._get_expected_share_detailed_response(self.share) 

153 expected['share'].pop('snapshot_support') 

154 self.assertEqual(expected, res_dict) 

155 

156 @ddt.data("2.2", "2.3") 

157 def test_share_create_with_snapshot_support_without_cg(self, microversion): 

158 self.mock_object(share_api.API, 'create', self.create_mock) 

159 body = {"share": copy.deepcopy(self.share)} 

160 req = fakes.HTTPRequest.blank('/v1/fake/shares', version=microversion) 

161 

162 res_dict = self.controller.create(req, body) 

163 

164 self.mock_policy_check.assert_called_once_with( 

165 req.environ['manila.context'], self.resource_name, 'create') 

166 expected = self._get_expected_share_detailed_response(self.share) 

167 self.assertEqual(expected, res_dict) 

168 

169 def test_share_create_with_valid_default_share_type(self): 

170 self.mock_object(share_types, 'get_share_type_by_name', 

171 mock.Mock(return_value=self.vt)) 

172 CONF.set_default("default_share_type", self.vt['name']) 

173 self.mock_object(share_api.API, 'create', self.create_mock) 

174 

175 body = {"share": copy.deepcopy(self.share)} 

176 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

177 res_dict = self.controller.create(req, body) 

178 

179 self.mock_policy_check.assert_called_once_with( 

180 req.environ['manila.context'], self.resource_name, 'create') 

181 expected = self._get_expected_share_detailed_response(self.share) 

182 expected['share'].pop('snapshot_support') 

183 share_types.get_share_type_by_name.assert_called_once_with( 

184 utils.IsAMatcher(context.RequestContext), self.vt['name']) 

185 self.assertEqual(expected, res_dict) 

186 

187 def test_share_create_with_invalid_default_share_type(self): 

188 self.mock_object( 

189 share_types, 'get_default_share_type', 

190 mock.Mock(side_effect=exception.ShareTypeNotFoundByName( 

191 self.vt['name'])), 

192 ) 

193 CONF.set_default("default_share_type", self.vt['name']) 

194 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

195 

196 self.assertRaises(exception.ShareTypeNotFoundByName, 

197 self.controller.create, req, {'share': self.share}) 

198 self.mock_policy_check.assert_called_once_with( 

199 req.environ['manila.context'], self.resource_name, 'create') 

200 share_types.get_default_share_type.assert_called_once_with() 

201 

202 def test_share_create_with_dhss_true_and_network_notexist(self): 

203 fake_share_type = { 

204 'id': 'fake_volume_type_id', 

205 'name': 'fake_volume_type_name', 

206 'extra_specs': { 

207 'driver_handles_share_servers': True, 

208 } 

209 } 

210 self.mock_object( 

211 share_types, 'get_default_share_type', 

212 mock.Mock(return_value=fake_share_type), 

213 ) 

214 CONF.set_default("default_share_type", fake_share_type['name']) 

215 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

216 

217 self.assertRaises(webob.exc.HTTPBadRequest, 

218 self.controller.create, req, {'share': self.share}) 

219 self.mock_policy_check.assert_called_once_with( 

220 req.environ['manila.context'], self.resource_name, 'create') 

221 share_types.get_default_share_type.assert_called_once_with() 

222 

223 def test_share_create_with_share_net(self): 

224 shr = { 

225 "size": 100, 

226 "name": "Share Test Name", 

227 "description": "Share Test Desc", 

228 "share_proto": "fakeproto", 

229 "availability_zone": "zone1:host1", 

230 "share_network_id": "fakenetid" 

231 } 

232 fake_network = {'id': 'fakenetid'} 

233 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

234 display_name=shr['name'], 

235 display_description=shr['description'], 

236 size=shr['size'], 

237 share_proto=shr['share_proto'].upper(), 

238 availability_zone=shr['availability_zone'], 

239 share_network_id=shr['share_network_id'])) 

240 self.mock_object(share_api.API, 'create', create_mock) 

241 self.mock_object(share_api.API, 'get_share_network', mock.Mock( 

242 return_value=fake_network)) 

243 self.mock_object(common, 'check_share_network_is_active', 

244 mock.Mock(return_value=True)) 

245 self.mock_object( 

246 db, 'share_network_subnets_get_all_by_availability_zone_id', 

247 mock.Mock(return_value={'id': 'fakesubnetid'})) 

248 

249 body = {"share": copy.deepcopy(shr)} 

250 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

251 res_dict = self.controller.create(req, body) 

252 

253 self.mock_policy_check.assert_called_once_with( 

254 req.environ['manila.context'], self.resource_name, 'create') 

255 expected = self._get_expected_share_detailed_response(shr) 

256 expected['share'].pop('snapshot_support') 

257 common.check_share_network_is_active.assert_called_once_with( 

258 fake_network) 

259 self.assertEqual(expected, res_dict) 

260 # pylint: disable=unsubscriptable-object 

261 self.assertEqual("fakenetid", 

262 create_mock.call_args[1]['share_network_id']) 

263 

264 def test_share_create_mount_point_name(self): 

265 shr = { 

266 "size": 100, 

267 "name": "Share Test Name", 

268 "description": "Share Test Desc", 

269 "share_proto": "fakeproto", 

270 "mount_point_name": "fake_mp" 

271 } 

272 fake_network = {'id': 'fakenetid'} 

273 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

274 display_name=shr['name'], 

275 display_description=shr['description'], 

276 size=shr['size'], 

277 share_proto=shr['share_proto'].upper(), 

278 mount_point_name=shr['mount_point_name'])) 

279 self.mock_object(share_api.API, 'create', create_mock) 

280 self.mock_object(share_api.API, 'get_share_network', mock.Mock( 

281 return_value=fake_network)) 

282 self.mock_object(common, 'check_share_network_is_active', 

283 mock.Mock(return_value=True)) 

284 self.mock_object( 

285 db, 'share_network_subnets_get_all_by_availability_zone_id', 

286 mock.Mock(return_value={'id': 'fakesubnetid'})) 

287 

288 body = {"share": copy.deepcopy(shr)} 

289 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

290 self.controller.create(req, body) 

291 

292 self.mock_policy_check.assert_called_once_with( 

293 req.environ['manila.context'], self.resource_name, 'create') 

294 

295 def test_share_create_with_share_net_not_active(self): 

296 shr = { 

297 "size": 100, 

298 "name": "Share Test Name", 

299 "description": "Share Test Desc", 

300 "share_proto": "fakeproto", 

301 "availability_zone": "zone1:host1", 

302 "share_network_id": "fakenetid" 

303 } 

304 share_network = db_utils.create_share_network( 

305 status=constants.STATUS_NETWORK_CHANGE) 

306 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

307 display_name=shr['name'], 

308 display_description=shr['description'], 

309 size=shr['size'], 

310 share_proto=shr['share_proto'].upper(), 

311 availability_zone=shr['availability_zone'], 

312 share_network_id=shr['share_network_id'])) 

313 self.mock_object(share_api.API, 'create', create_mock) 

314 self.mock_object(share_api.API, 'get_share_network', mock.Mock( 

315 return_value=share_network)) 

316 self.mock_object(common, 'check_share_network_is_active', 

317 mock.Mock(side_effect=webob.exc.HTTPBadRequest())) 

318 

319 body = {"share": copy.deepcopy(shr)} 

320 req = fakes.HTTPRequest.blank('/shares') 

321 self.assertRaises( 

322 webob.exc.HTTPBadRequest, 

323 self.controller.create, 

324 req, 

325 body) 

326 

327 self.mock_policy_check.assert_called_once_with( 

328 req.environ['manila.context'], self.resource_name, 'create') 

329 common.check_share_network_is_active.assert_called_once_with( 

330 share_network) 

331 

332 def test_share_create_from_snapshot_without_share_net_no_parent(self): 

333 shr = { 

334 "size": 100, 

335 "name": "Share Test Name", 

336 "description": "Share Test Desc", 

337 "share_proto": "fakeproto", 

338 "availability_zone": "zone1:host1", 

339 "snapshot_id": 333, 

340 "share_network_id": None, 

341 } 

342 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

343 display_name=shr['name'], 

344 display_description=shr['description'], 

345 size=shr['size'], 

346 share_proto=shr['share_proto'].upper(), 

347 availability_zone=shr['availability_zone'], 

348 snapshot_id=shr['snapshot_id'], 

349 share_network_id=shr['share_network_id'])) 

350 self.mock_object(share_api.API, 'create', create_mock) 

351 body = {"share": copy.deepcopy(shr)} 

352 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

353 

354 res_dict = self.controller.create(req, body) 

355 

356 self.mock_policy_check.assert_called_once_with( 

357 req.environ['manila.context'], self.resource_name, 'create') 

358 expected = self._get_expected_share_detailed_response(shr) 

359 expected['share'].pop('snapshot_support') 

360 self.assertEqual(expected, res_dict) 

361 

362 def test_share_create_from_snapshot_without_share_net_parent_exists(self): 

363 shr = { 

364 "size": 100, 

365 "name": "Share Test Name", 

366 "description": "Share Test Desc", 

367 "share_proto": "fakeproto", 

368 "availability_zone": "zone1:host1", 

369 "snapshot_id": 333, 

370 "share_network_id": None, 

371 } 

372 parent_share_net = 444 

373 fake_share_net = {'id': parent_share_net} 

374 share_net_subnets = [db_utils.create_share_network_subnet( 

375 id='fake_subnet_id', share_network_id=fake_share_net['id'])] 

376 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

377 display_name=shr['name'], 

378 display_description=shr['description'], 

379 size=shr['size'], 

380 share_proto=shr['share_proto'].upper(), 

381 snapshot_id=shr['snapshot_id'], 

382 instance=dict( 

383 availability_zone=shr['availability_zone'], 

384 share_network_id=shr['share_network_id']))) 

385 self.mock_object(share_api.API, 'create', create_mock) 

386 self.mock_object(share_api.API, 'get_snapshot', 

387 stubs.stub_snapshot_get) 

388 parent_share = stubs.stub_share( 

389 '1', instance={'share_network_id': parent_share_net}, 

390 create_share_from_snapshot_support=True) 

391 self.mock_object(share_api.API, 'get', mock.Mock( 

392 return_value=parent_share)) 

393 self.mock_object(share_api.API, 'get_share_network', mock.Mock( 

394 return_value=fake_share_net)) 

395 self.mock_object(common, 'check_share_network_is_active', 

396 mock.Mock(return_value=True)) 

397 self.mock_object( 

398 db, 'share_network_subnets_get_all_by_availability_zone_id', 

399 mock.Mock(return_value=share_net_subnets)) 

400 

401 body = {"share": copy.deepcopy(shr)} 

402 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

403 

404 res_dict = self.controller.create(req, body) 

405 

406 self.mock_policy_check.assert_called_once_with( 

407 req.environ['manila.context'], self.resource_name, 'create') 

408 expected = self._get_expected_share_detailed_response(shr) 

409 expected['share'].pop('snapshot_support') 

410 common.check_share_network_is_active.assert_called_once_with( 

411 fake_share_net) 

412 self.assertEqual(expected, res_dict) 

413 # pylint: disable=unsubscriptable-object 

414 self.assertEqual(parent_share_net, 

415 create_mock.call_args[1]['share_network_id']) 

416 

417 def test_share_create_from_snapshot_with_share_net_equals_parent(self): 

418 parent_share_net = 444 

419 shr = { 

420 "size": 100, 

421 "name": "Share Test Name", 

422 "description": "Share Test Desc", 

423 "share_proto": "fakeproto", 

424 "availability_zone": "zone1:host1", 

425 "snapshot_id": 333, 

426 "share_network_id": parent_share_net 

427 } 

428 fake_share_net = {'id': parent_share_net} 

429 share_net_subnets = [db_utils.create_share_network_subnet( 

430 id='fake_subnet_id', share_network_id=fake_share_net['id'])] 

431 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

432 display_name=shr['name'], 

433 display_description=shr['description'], 

434 size=shr['size'], 

435 share_proto=shr['share_proto'].upper(), 

436 snapshot_id=shr['snapshot_id'], 

437 instance=dict( 

438 availability_zone=shr['availability_zone'], 

439 share_network_id=shr['share_network_id']))) 

440 self.mock_object(share_api.API, 'create', create_mock) 

441 self.mock_object(share_api.API, 'get_snapshot', 

442 stubs.stub_snapshot_get) 

443 self.mock_object(common, 'check_share_network_is_active', 

444 mock.Mock(return_value=True)) 

445 parent_share = stubs.stub_share( 

446 '1', instance={'share_network_id': parent_share_net}, 

447 create_share_from_snapshot_support=True) 

448 self.mock_object(share_api.API, 'get', mock.Mock( 

449 return_value=parent_share)) 

450 self.mock_object(share_api.API, 'get_share_network', mock.Mock( 

451 return_value=fake_share_net)) 

452 self.mock_object( 

453 db, 'share_network_subnets_get_all_by_availability_zone_id', 

454 mock.Mock(return_value=share_net_subnets)) 

455 

456 body = {"share": copy.deepcopy(shr)} 

457 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

458 

459 res_dict = self.controller.create(req, body) 

460 

461 self.mock_policy_check.assert_called_once_with( 

462 req.environ['manila.context'], self.resource_name, 'create') 

463 expected = self._get_expected_share_detailed_response(shr) 

464 expected['share'].pop('snapshot_support') 

465 common.check_share_network_is_active.assert_called_once_with( 

466 fake_share_net) 

467 self.assertEqual(expected, res_dict) 

468 # pylint: disable=unsubscriptable-object 

469 self.assertEqual(parent_share_net, 

470 create_mock.call_args[1]['share_network_id']) 

471 

472 def test_share_create_from_snapshot_invalid_share_net(self): 

473 self.mock_object(share_api.API, 'create') 

474 shr = { 

475 "size": 100, 

476 "name": "Share Test Name", 

477 "description": "Share Test Desc", 

478 "share_proto": "fakeproto", 

479 "availability_zone": "zone1:host1", 

480 "snapshot_id": 333, 

481 "share_network_id": 1234 

482 } 

483 body = {"share": shr} 

484 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

485 

486 self.assertRaises(webob.exc.HTTPBadRequest, 

487 self.controller.create, 

488 req, 

489 body) 

490 self.mock_policy_check.assert_called_once_with( 

491 req.environ['manila.context'], self.resource_name, 'create') 

492 

493 def test_share_create_from_mount_point_name(self): 

494 parent_share_net = 444 

495 shr = { 

496 "size": 100, 

497 "name": "Share Test Name", 

498 "description": "Share Test Desc", 

499 "share_proto": "fakeproto", 

500 "availability_zone": "zone1:host1", 

501 "snapshot_id": 333, 

502 "share_network_id": parent_share_net, 

503 "mount_point_name": "fake_mp" 

504 } 

505 fake_share_net = {'id': parent_share_net} 

506 share_net_subnets = [db_utils.create_share_network_subnet( 

507 id='fake_subnet_id', share_network_id=fake_share_net['id'])] 

508 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

509 display_name=shr['name'], 

510 display_description=shr['description'], 

511 size=shr['size'], 

512 share_proto=shr['share_proto'].upper(), 

513 snapshot_id=shr['snapshot_id'], 

514 mount_point_name=shr['mount_point_name'], 

515 instance=dict( 

516 availability_zone=shr['availability_zone'], 

517 share_network_id=shr['share_network_id'], 

518 ))) 

519 self.mock_object(share_api.API, 'create', create_mock) 

520 self.mock_object(share_api.API, 'get_snapshot', 

521 stubs.stub_snapshot_get) 

522 self.mock_object(common, 'check_share_network_is_active', 

523 mock.Mock(return_value=True)) 

524 parent_share = stubs.stub_share( 

525 '1', instance={'share_network_id': parent_share_net}, 

526 create_share_from_snapshot_support=True) 

527 self.mock_object(share_api.API, 'get', mock.Mock( 

528 return_value=parent_share)) 

529 self.mock_object(share_api.API, 'get_share_network', mock.Mock( 

530 return_value=fake_share_net)) 

531 self.mock_object( 

532 db, 'share_network_subnets_get_all_by_availability_zone_id', 

533 mock.Mock(return_value=share_net_subnets)) 

534 

535 body = {"share": copy.deepcopy(shr)} 

536 req = fakes.HTTPRequest.blank('/v1/fake/shares', version='2.84') 

537 res_dict = self.controller.create(req, body) 

538 self.assertEqual(res_dict['share']['project_id'], 'fakeproject') 

539 

540 @ddt.data( 

541 {'name': 'name1', 'description': 'x' * 256}, 

542 {'name': 'x' * 256, 'description': 'description1'}, 

543 ) 

544 @ddt.unpack 

545 def test_share_create_invalid_input(self, name, description): 

546 self.mock_object(share_api.API, 'create') 

547 shr = { 

548 "size": 100, 

549 "name": name, 

550 "description": description, 

551 "share_proto": "fakeproto", 

552 "availability_zone": "zone1:host1", 

553 } 

554 body = {"share": shr} 

555 req = fakes.HTTPRequest.blank('/v1/fake/shares') 

556 

557 self.assertRaises(exception.InvalidInput, 

558 self.controller.create, 

559 req, 

560 body) 

561 self.mock_policy_check.assert_called_once_with( 

562 req.environ['manila.context'], self.resource_name, 'create') 

563 

564 @ddt.data("1.0", "2.0") 

565 def test_share_create_from_snapshot_not_supported(self, microversion): 

566 # This create operation should work, because the 1.0 API doesn't check 

567 # create_share_from_snapshot_support. 

568 

569 parent_share_net = 444 

570 shr = { 

571 "size": 100, 

572 "name": "Share Test Name", 

573 "description": "Share Test Desc", 

574 "share_proto": "fakeproto", 

575 "availability_zone": "zone1:host1", 

576 "snapshot_id": 333, 

577 "share_network_id": parent_share_net 

578 } 

579 fake_share_net = {'id': parent_share_net} 

580 share_net_subnets = [db_utils.create_share_network_subnet( 

581 id='fake_subnet_id', share_network_id=fake_share_net['id'])] 

582 create_mock = mock.Mock(return_value=stubs.stub_share('1', 

583 display_name=shr['name'], 

584 display_description=shr['description'], 

585 size=shr['size'], 

586 share_proto=shr['share_proto'].upper(), 

587 snapshot_id=shr['snapshot_id'], 

588 instance=dict( 

589 availability_zone=shr['availability_zone'], 

590 share_network_id=shr['share_network_id']))) 

591 self.mock_object(share_api.API, 'create', create_mock) 

592 self.mock_object(share_api.API, 'get_snapshot', 

593 stubs.stub_snapshot_get) 

594 self.mock_object(common, 'check_share_network_is_active', 

595 mock.Mock(return_value=True)) 

596 parent_share = stubs.stub_share( 

597 '1', instance={'share_network_id': parent_share_net}, 

598 create_share_from_snapshot_support=False) 

599 self.mock_object(share_api.API, 'get', mock.Mock( 

600 return_value=parent_share)) 

601 self.mock_object(share_api.API, 'get_share_network', mock.Mock( 

602 return_value=fake_share_net)) 

603 self.mock_object( 

604 db, 'share_network_subnets_get_all_by_availability_zone_id', 

605 mock.Mock(return_value=share_net_subnets)) 

606 

607 body = {"share": copy.deepcopy(shr)} 

608 req = fakes.HTTPRequest.blank('/v1/fake/shares', version=microversion) 

609 

610 res_dict = self.controller.create(req, body) 

611 

612 self.mock_policy_check.assert_called_once_with( 

613 req.environ['manila.context'], self.resource_name, 'create') 

614 expected = self._get_expected_share_detailed_response(shr) 

615 expected['share'].pop('snapshot_support') 

616 common.check_share_network_is_active.assert_called_once_with( 

617 fake_share_net) 

618 self.assertDictEqual(expected, res_dict) 

619 # pylint: disable=unsubscriptable-object 

620 self.assertEqual(parent_share_net, 

621 create_mock.call_args[1]['share_network_id']) 

622 

623 def test_share_creation_fails_with_bad_size(self): 

624 shr = {"size": '', 

625 "name": "Share Test Name", 

626 "description": "Share Test Desc", 

627 "share_proto": "fakeproto", 

628 "availability_zone": "zone1:host1"} 

629 body = {"share": shr} 

630 req = fakes.HTTPRequest.blank('/fake/shares') 

631 self.assertRaises(exception.InvalidInput, 

632 self.controller.create, 

633 req, 

634 body) 

635 self.mock_policy_check.assert_called_once_with( 

636 req.environ['manila.context'], self.resource_name, 'create') 

637 

638 def test_share_create_no_body(self): 

639 body = {} 

640 req = fakes.HTTPRequest.blank('/fake/shares') 

641 self.assertRaises(webob.exc.HTTPUnprocessableEntity, 

642 self.controller.create, 

643 req, 

644 body) 

645 self.mock_policy_check.assert_called_once_with( 

646 req.environ['manila.context'], self.resource_name, 'create') 

647 

648 def test_share_creation_fails_with_invalid_share_type(self): 

649 shr = { 

650 "size": 1, 

651 "name": "Share Test Name", 

652 "description": "Share Test Desc", 

653 "share_proto": "fakeproto", 

654 "availability_zone": "zone1:host1", 

655 "share_type": "Invalid share type" 

656 } 

657 body = {"share": shr} 

658 req = fakes.HTTPRequest.blank('/fake/shares') 

659 with mock.patch('manila.share.share_types.get_share_type_by_name', 

660 side_effect=exception.InvalidShareType(reason='')): 

661 self.assertRaises(webob.exc.HTTPBadRequest, 

662 self.controller.create, 

663 req, 

664 body) 

665 self.mock_policy_check.assert_called_once_with( 

666 req.environ['manila.context'], self.resource_name, 'create') 

667 

668 def test_share_create_invalid_availability_zone(self): 

669 self.mock_object( 

670 db, 

671 'availability_zone_get', 

672 mock.Mock(side_effect=exception.AvailabilityZoneNotFound(id='id')) 

673 ) 

674 body = {"share": copy.deepcopy(self.share)} 

675 

676 req = fakes.HTTPRequest.blank('/fake/shares') 

677 self.assertRaises(webob.exc.HTTPNotFound, 

678 self.controller.create, 

679 req, 

680 body) 

681 

682 @ddt.data((exception.ShareNetworkNotFound(share_network_id='fake'), 

683 webob.exc.HTTPNotFound), 

684 (mock.Mock(), webob.exc.HTTPBadRequest)) 

685 @ddt.unpack 

686 def test_share_create_invalid_subnet(self, share_network_side_effect, 

687 exception_to_raise): 

688 fake_share_with_sn = copy.deepcopy(self.share) 

689 fake_share_with_sn['share_network_id'] = 'fakenetid' 

690 self.mock_object(db, 'share_network_get', 

691 mock.Mock(side_effect=share_network_side_effect)) 

692 self.mock_object( 

693 db, 'share_network_subnets_get_all_by_availability_zone_id', 

694 mock.Mock(return_value=None)) 

695 self.mock_object(common, 'check_share_network_is_active') 

696 

697 body = {"share": fake_share_with_sn} 

698 

699 req = fakes.HTTPRequest.blank('/fake/shares') 

700 self.assertRaises(exception_to_raise, 

701 self.controller.create, 

702 req, 

703 body) 

704 

705 def test_share_show(self): 

706 req = fakes.HTTPRequest.blank('/fake/shares/1') 

707 expected = self._get_expected_share_detailed_response() 

708 expected['share'].pop('snapshot_support') 

709 

710 res_dict = self.controller.show(req, '1') 

711 

712 self.assertEqual(expected, res_dict) 

713 

714 def test_share_show_with_share_type_name(self): 

715 req = fakes.HTTPRequest.blank('/fake/shares/1', version='2.6') 

716 res_dict = self.controller.show(req, '1') 

717 expected = self._get_expected_share_detailed_response() 

718 expected['share']['share_type_name'] = None 

719 expected['share']['task_state'] = None 

720 self.assertEqual(expected, res_dict) 

721 

722 def test_share_show_admin(self): 

723 req = fakes.HTTPRequest.blank('/fake/shares/1', use_admin_context=True) 

724 expected = self._get_expected_share_detailed_response(admin=True) 

725 expected['share'].pop('snapshot_support') 

726 

727 res_dict = self.controller.show(req, '1') 

728 

729 self.assertEqual(expected, res_dict) 

730 

731 def test_share_show_no_share(self): 

732 self.mock_object(share_api.API, 'get', 

733 stubs.stub_share_get_notfound) 

734 req = fakes.HTTPRequest.blank('/fake/shares/1') 

735 self.assertRaises(webob.exc.HTTPNotFound, 

736 self.controller.show, 

737 req, '1') 

738 

739 def test_share_delete(self): 

740 req = fakes.HTTPRequest.blank('/fake/shares/1') 

741 resp = self.controller.delete(req, 1) 

742 self.assertEqual(202, resp.status_int) 

743 

744 def test_share_update(self): 

745 shr = self.share 

746 body = {"share": shr} 

747 

748 req = fakes.HTTPRequest.blank('/share/1') 

749 

750 res_dict = self.controller.update(req, 1, body) 

751 

752 self.mock_policy_check.assert_called_once_with( 

753 req.environ['manila.context'], self.resource_name, 'update') 

754 self.assertEqual(shr["display_name"], res_dict['share']["name"]) 

755 self.assertEqual(shr["display_description"], 

756 res_dict['share']["description"]) 

757 self.assertEqual(shr['is_public'], 

758 res_dict['share']['is_public']) 

759 

760 def test_share_not_updates_size(self): 

761 req = fakes.HTTPRequest.blank('/share/1') 

762 

763 res_dict = self.controller.update(req, 1, {"share": self.share}) 

764 

765 self.mock_policy_check.assert_called_once_with( 

766 req.environ['manila.context'], self.resource_name, 'update') 

767 self.assertNotEqual(res_dict['share']["size"], self.share["size"]) 

768 

769 def test_share_delete_no_share(self): 

770 self.mock_object(share_api.API, 'get', 

771 stubs.stub_share_get_notfound) 

772 req = fakes.HTTPRequest.blank('/fake/shares/1') 

773 self.assertRaises(webob.exc.HTTPNotFound, 

774 self.controller.delete, 

775 req, 

776 1) 

777 

778 def _share_list_summary_with_search_opts(self, use_admin_context): 

779 search_opts = { 

780 'name': 'fake_name', 

781 'status': constants.STATUS_AVAILABLE, 

782 'share_server_id': 'fake_share_server_id', 

783 'share_type_id': 'fake_share_type_id', 

784 'snapshot_id': 'fake_snapshot_id', 

785 'share_network_id': 'fake_share_network_id', 

786 'metadata': '%7B%27k1%27%3A+%27v1%27%7D', # serialized k1=v1 

787 'extra_specs': '%7B%27k2%27%3A+%27v2%27%7D', # serialized k2=v2 

788 'sort_key': 'fake_sort_key', 

789 'sort_dir': 'fake_sort_dir', 

790 'limit': '1', 

791 'offset': '1', 

792 'is_public': 'False', 

793 } 

794 if use_admin_context: 

795 search_opts['host'] = 'fake_host' 

796 # fake_key should be filtered for non-admin 

797 url = '/fake/shares?fake_key=fake_value' 

798 for k, v in search_opts.items(): 

799 url = url + '&' + k + '=' + v 

800 req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) 

801 

802 shares = [ 

803 {'id': 'id1', 'display_name': 'n1'}, 

804 {'id': 'id2', 'display_name': 'n2'}, 

805 {'id': 'id3', 'display_name': 'n3'}, 

806 ] 

807 self.mock_object(share_api.API, 'get_all', 

808 mock.Mock(return_value=[shares[1]])) 

809 

810 result = self.controller.index(req) 

811 

812 search_opts_expected = { 

813 'display_name': search_opts['name'], 

814 'status': search_opts['status'], 

815 'share_server_id': search_opts['share_server_id'], 

816 'share_type_id': search_opts['share_type_id'], 

817 'snapshot_id': search_opts['snapshot_id'], 

818 'share_network_id': search_opts['share_network_id'], 

819 'metadata': {'k1': 'v1'}, 

820 'extra_specs': {'k2': 'v2'}, 

821 'is_public': 'False', 

822 'limit': '1', 

823 'offset': '1' 

824 } 

825 

826 if use_admin_context: 

827 search_opts_expected.update({'fake_key': 'fake_value'}) 

828 search_opts_expected['host'] = search_opts['host'] 

829 share_api.API.get_all.assert_called_once_with( 

830 req.environ['manila.context'], 

831 sort_key=search_opts['sort_key'], 

832 sort_dir=search_opts['sort_dir'], 

833 search_opts=search_opts_expected, 

834 ) 

835 self.assertEqual(1, len(result['shares'])) 

836 self.assertEqual(shares[1]['id'], result['shares'][0]['id']) 

837 self.assertEqual( 

838 shares[1]['display_name'], result['shares'][0]['name']) 

839 

840 def test_share_list_summary_with_search_opts_by_non_admin(self): 

841 self._share_list_summary_with_search_opts(use_admin_context=False) 

842 

843 def test_share_list_summary_with_search_opts_by_admin(self): 

844 self._share_list_summary_with_search_opts(use_admin_context=True) 

845 

846 def test_share_list_summary(self): 

847 self.mock_object(share_api.API, 'get_all', 

848 stubs.stub_share_get_all_by_project) 

849 req = fakes.HTTPRequest.blank('/fake/shares') 

850 res_dict = self.controller.index(req) 

851 expected = { 

852 'shares': [ 

853 { 

854 'name': 'displayname', 

855 'id': '1', 

856 'links': [ 

857 { 

858 'href': 'http://localhost/share/v1/fake/shares/1', 

859 'rel': 'self' 

860 }, 

861 { 

862 'href': 'http://localhost/share/fake/shares/1', 

863 'rel': 'bookmark' 

864 } 

865 ], 

866 } 

867 ] 

868 } 

869 self.assertEqual(expected, res_dict) 

870 

871 def _share_list_detail_with_search_opts(self, use_admin_context): 

872 search_opts = { 

873 'name': 'fake_name', 

874 'status': constants.STATUS_AVAILABLE, 

875 'share_server_id': 'fake_share_server_id', 

876 'share_type_id': 'fake_share_type_id', 

877 'snapshot_id': 'fake_snapshot_id', 

878 'share_network_id': 'fake_share_network_id', 

879 'metadata': '%7B%27k1%27%3A+%27v1%27%7D', # serialized k1=v1 

880 'extra_specs': '%7B%27k2%27%3A+%27v2%27%7D', # serialized k2=v2 

881 'sort_key': 'fake_sort_key', 

882 'sort_dir': 'fake_sort_dir', 

883 'limit': '1', 

884 'offset': '1', 

885 'is_public': 'False', 

886 } 

887 if use_admin_context: 

888 search_opts['host'] = 'fake_host' 

889 # fake_key should be filtered for non-admin 

890 url = '/fake/shares/detail?fake_key=fake_value' 

891 for k, v in search_opts.items(): 

892 url = url + '&' + k + '=' + v 

893 req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) 

894 

895 shares = [ 

896 {'id': 'id1', 'display_name': 'n1'}, 

897 { 

898 'id': 'id2', 

899 'display_name': 'n2', 

900 'status': constants.STATUS_AVAILABLE, 

901 'snapshot_id': 'fake_snapshot_id', 

902 'instance': {'host': 'fake_host', 

903 'share_network_id': 'fake_share_network_id', 

904 'share_type_id': 'fake_share_type_id'}, 

905 }, 

906 {'id': 'id3', 'display_name': 'n3'}, 

907 ] 

908 self.mock_object(share_api.API, 'get_all', 

909 mock.Mock(return_value=[shares[1]])) 

910 

911 result = self.controller.detail(req) 

912 

913 search_opts_expected = { 

914 'display_name': search_opts['name'], 

915 'status': search_opts['status'], 

916 'share_server_id': search_opts['share_server_id'], 

917 'share_type_id': search_opts['share_type_id'], 

918 'snapshot_id': search_opts['snapshot_id'], 

919 'share_network_id': search_opts['share_network_id'], 

920 'metadata': {'k1': 'v1'}, 

921 'extra_specs': {'k2': 'v2'}, 

922 'is_public': 'False', 

923 'limit': '1', 

924 'offset': '1' 

925 } 

926 if use_admin_context: 

927 search_opts_expected.update({'fake_key': 'fake_value'}) 

928 search_opts_expected['host'] = search_opts['host'] 

929 share_api.API.get_all.assert_called_once_with( 

930 req.environ['manila.context'], 

931 sort_key=search_opts['sort_key'], 

932 sort_dir=search_opts['sort_dir'], 

933 search_opts=search_opts_expected, 

934 ) 

935 self.assertEqual(1, len(result['shares'])) 

936 self.assertEqual(shares[1]['id'], result['shares'][0]['id']) 

937 self.assertEqual( 

938 shares[1]['display_name'], result['shares'][0]['name']) 

939 self.assertEqual( 

940 shares[1]['snapshot_id'], result['shares'][0]['snapshot_id']) 

941 self.assertEqual( 

942 shares[1]['status'], result['shares'][0]['status']) 

943 self.assertEqual( 

944 shares[1]['instance']['share_type_id'], 

945 result['shares'][0]['share_type']) 

946 self.assertEqual( 

947 shares[1]['snapshot_id'], result['shares'][0]['snapshot_id']) 

948 if use_admin_context: 

949 self.assertEqual( 

950 shares[1]['instance']['host'], result['shares'][0]['host']) 

951 self.assertEqual( 

952 shares[1]['instance']['share_network_id'], 

953 result['shares'][0]['share_network_id']) 

954 

955 def test_share_list_detail_with_search_opts_by_non_admin(self): 

956 self._share_list_detail_with_search_opts(use_admin_context=False) 

957 

958 def test_share_list_detail_with_search_opts_by_admin(self): 

959 self._share_list_detail_with_search_opts(use_admin_context=True) 

960 

961 def _list_detail_common_expected(self, admin=False): 

962 share_dict = { 

963 'status': 'fakestatus', 

964 'description': 'displaydesc', 

965 'export_location': 'fake_location', 

966 'export_locations': ['fake_location', 'fake_location2'], 

967 'availability_zone': 'fakeaz', 

968 'name': 'displayname', 

969 'share_proto': 'FAKEPROTO', 

970 'metadata': {}, 

971 'project_id': 'fakeproject', 

972 

973 'id': '1', 

974 'snapshot_id': '2', 

975 'snapshot_support': True, 

976 'share_network_id': None, 

977 'created_at': datetime.datetime(1, 1, 1, 1, 1, 1), 

978 'size': 1, 

979 'share_type': '1', 

980 'volume_type': '1', 

981 'is_public': False, 

982 'links': [ 

983 { 

984 'href': 'http://localhost/share/v1/fake/shares/1', 

985 'rel': 'self' 

986 }, 

987 { 

988 'href': 'http://localhost/share/fake/shares/1', 

989 'rel': 'bookmark' 

990 } 

991 ], 

992 } 

993 if admin: 993 ↛ 994line 993 didn't jump to line 994 because the condition on line 993 was never true

994 share_dict['host'] = 'fakehost' 

995 return {'shares': [share_dict]} 

996 

997 def _list_detail_test_common(self, req, expected): 

998 self.mock_object(share_api.API, 'get_all', 

999 stubs.stub_share_get_all_by_project) 

1000 res_dict = self.controller.detail(req) 

1001 self.assertEqual(expected, res_dict) 

1002 self.assertEqual(res_dict['shares'][0]['volume_type'], 

1003 res_dict['shares'][0]['share_type']) 

1004 

1005 def test_share_list_detail(self): 

1006 env = {'QUERY_STRING': 'name=Share+Test+Name'} 

1007 req = fakes.HTTPRequest.blank('/fake/shares/detail', environ=env) 

1008 expected = self._list_detail_common_expected() 

1009 expected['shares'][0].pop('snapshot_support') 

1010 self._list_detail_test_common(req, expected) 

1011 

1012 def test_share_list_detail_with_task_state(self): 

1013 env = {'QUERY_STRING': 'name=Share+Test+Name'} 

1014 req = fakes.HTTPRequest.blank('/fake/shares/detail', environ=env, 

1015 version="2.5") 

1016 expected = self._list_detail_common_expected() 

1017 expected['shares'][0]['task_state'] = None 

1018 self._list_detail_test_common(req, expected) 

1019 

1020 def test_remove_invalid_options(self): 

1021 ctx = context.RequestContext('fakeuser', 'fakeproject', is_admin=False) 

1022 search_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'} 

1023 expected_opts = {'a': 'a', 'c': 'c'} 

1024 allowed_opts = ['a', 'c'] 

1025 common.remove_invalid_options(ctx, search_opts, allowed_opts) 

1026 self.assertEqual(expected_opts, search_opts) 

1027 

1028 def test_remove_invalid_options_admin(self): 

1029 ctx = context.RequestContext('fakeuser', 'fakeproject', is_admin=True) 

1030 search_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'} 

1031 expected_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'} 

1032 allowed_opts = ['a', 'c'] 

1033 common.remove_invalid_options(ctx, search_opts, allowed_opts) 

1034 self.assertEqual(expected_opts, search_opts) 

1035 

1036 

1037def _fake_access_get(self, ctxt, access_id): 

1038 

1039 class Access(object): 

1040 def __init__(self, **kwargs): 

1041 self.STATE_NEW = 'fake_new' 

1042 self.STATE_ACTIVE = 'fake_active' 

1043 self.STATE_ERROR = 'fake_error' 

1044 self.params = kwargs 

1045 self.params['state'] = self.STATE_NEW 

1046 self.share_id = kwargs.get('share_id') 

1047 self.id = access_id 

1048 

1049 def __getitem__(self, item): 

1050 return self.params[item] 

1051 

1052 access = Access(access_id=access_id, share_id='fake_share_id') 

1053 return access 

1054 

1055 

1056@ddt.ddt 

1057class ShareActionsTest(test.TestCase): 

1058 

1059 def setUp(self): 

1060 super(ShareActionsTest, self).setUp() 

1061 self.controller = shares.ShareController() 

1062 self.mock_object(share_api.API, 'get', stubs.stub_share_get) 

1063 self.mock_policy_check = self.mock_object(policy, 'check_policy') 

1064 

1065 @ddt.data( 

1066 {'access_type': 'ip', 'access_to': '127.0.0.1'}, 

1067 {'access_type': 'user', 'access_to': '1' * 4}, 

1068 {'access_type': 'user', 'access_to': '1' * 255}, 

1069 {'access_type': 'user', 'access_to': 'fake{.-_\'`}'}, 

1070 {'access_type': 'user', 'access_to': 'MYDOMAIN-Administrator'}, 

1071 {'access_type': 'user', 'access_to': 'test group name'}, 

1072 {'access_type': 'user', 'access_to': 'group$.-_\'`{}'}, 

1073 {'access_type': 'cert', 'access_to': 'x'}, 

1074 {'access_type': 'cert', 'access_to': 'tenant.example.com'}, 

1075 {'access_type': 'cert', 'access_to': 'x' * 64}, 

1076 {'access_type': 'cert', 'access_to': 'x' * 64, 

1077 'lock_visibility': True}, 

1078 {'access_type': 'cert', 'access_to': 'x' * 64, 'lock_deletion': True}, 

1079 {'access_type': 'cert', 'access_to': 'x' * 64, 'lock_deletion': True}, 

1080 {'access_type': 'cert', 'access_to': 'x' * 64, 'lock_deletion': True, 

1081 'lock_visibility': True, 'lock_reason': 'locked_for_testing'}, 

1082 ) 

1083 def test_allow_access(self, access): 

1084 self.mock_object(share_api.API, 

1085 'allow_access', 

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

1087 self.mock_object(self.controller._access_view_builder, 'view', 

1088 mock.Mock(return_value={'access': 

1089 {'fake': 'fake'}})) 

1090 self.mock_object(self.controller, '_create_access_locks') 

1091 

1092 id = 'fake_share_id' 

1093 body = {'os-allow_access': access} 

1094 expected = {'access': {'fake': 'fake'}} 

1095 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) 

1096 lock_visibility = access.pop('lock_visibility', None) 

1097 lock_deletion = access.pop('lock_deletion', None) 

1098 lock_reason = access.pop('lock_reason', None) 

1099 

1100 res = self.controller._allow_access( 

1101 req, id, body, lock_visibility=lock_visibility, 

1102 lock_deletion=lock_deletion, lock_reason=lock_reason 

1103 ) 

1104 

1105 self.assertEqual(expected, res) 

1106 self.mock_policy_check.assert_called_once_with( 

1107 req.environ['manila.context'], 'share', 'allow_access') 

1108 if lock_visibility or lock_deletion: 

1109 self.controller._create_access_locks.assert_called_once_with( 

1110 req.environ['manila.context'], 

1111 expected['access'], 

1112 lock_deletion=lock_deletion, 

1113 lock_visibility=lock_visibility, 

1114 lock_reason=lock_reason 

1115 ) 

1116 

1117 @ddt.data( 

1118 {'lock_visibility': True, 'lock_deletion': True, 

1119 'lock_reason': 'test lock reason'}, 

1120 {'lock_visibility': True, 'lock_deletion': False, 'lock_reason': None}, 

1121 {'lock_visibility': False, 'lock_deletion': True, 'lock_reason': None}, 

1122 ) 

1123 @ddt.unpack 

1124 def test__create_access_locks(self, lock_visibility, lock_deletion, 

1125 lock_reason): 

1126 access = { 

1127 'id': 'fake', 

1128 'access_type': 'ip', 

1129 'access_to': '127.0.0.1', 

1130 'share_id': 'fake_share_id' 

1131 } 

1132 mock_deletion_lock_create = mock.Mock() 

1133 lock_id = 'fake_lock_id' 

1134 if lock_deletion: 

1135 mock_deletion_lock_create = mock.Mock( 

1136 side_effect=[ 

1137 {'id': lock_id}, 

1138 {'id': f'{lock_id}2'}, 

1139 {'id': f'{lock_id}3'} 

1140 ] 

1141 ) 

1142 self.mock_object( 

1143 resource_locks.API, 'create', mock_deletion_lock_create 

1144 ) 

1145 

1146 id = 'fake_share_id' 

1147 req = fakes.HTTPRequest.blank( 

1148 '/tenant1/shares/%s/action' % id, version='2.82') 

1149 context = req.environ['manila.context'] 

1150 access['project_id'] = context.project_id 

1151 access['user_id'] = context.user_id 

1152 

1153 self.controller._create_access_locks( 

1154 req.environ['manila.context'], 

1155 access, 

1156 lock_deletion=lock_deletion, 

1157 lock_visibility=lock_visibility, 

1158 lock_reason=lock_reason 

1159 ) 

1160 

1161 restrict_calls = [] 

1162 if lock_deletion: 

1163 share_lock_reason = ( 

1164 constants.SHARE_LOCKED_BY_ACCESS_LOCK_REASON % 

1165 {'lock_id': lock_id} 

1166 ) 

1167 restrict_calls.append( 

1168 mock.call( 

1169 context, resource_id=access['id'], 

1170 resource_type='access_rule', 

1171 resource_action=constants.RESOURCE_ACTION_DELETE, 

1172 resource=access, 

1173 lock_reason=lock_reason 

1174 ) 

1175 ) 

1176 restrict_calls.append( 

1177 mock.call( 

1178 context, resource_id=access['share_id'], 

1179 resource_type='share', 

1180 resource_action=constants.RESOURCE_ACTION_DELETE, 

1181 lock_reason=share_lock_reason 

1182 ) 

1183 ) 

1184 if lock_visibility: 

1185 restrict_calls.append( 

1186 mock.call( 

1187 context, resource_id=access['id'], 

1188 resource_type='access_rule', 

1189 resource_action=constants.RESOURCE_ACTION_SHOW, 

1190 resource=access, 

1191 lock_reason=lock_reason 

1192 ) 

1193 ) 

1194 resource_locks.API.create.assert_has_calls(restrict_calls) 

1195 

1196 def test__create_access_visibility_locks_creation_failed(self): 

1197 access = { 

1198 'id': 'fake', 

1199 'access_type': 'ip', 

1200 'access_to': '127.0.0.1', 

1201 } 

1202 lock_reason = 'locked for testing' 

1203 self.mock_object( 

1204 resource_locks.API, 'create', 

1205 mock.Mock(side_effect=exception.NotAuthorized) 

1206 ) 

1207 

1208 id = 'fake_share_id' 

1209 req = fakes.HTTPRequest.blank( 

1210 '/tenant1/shares/%s/action' % id, version='2.82') 

1211 context = req.environ['manila.context'] 

1212 access['project_id'] = context.project_id 

1213 access['user_id'] = context.user_id 

1214 

1215 self.assertRaises( 

1216 webob.exc.HTTPBadRequest, 

1217 self.controller._create_access_locks, 

1218 req.environ['manila.context'], 

1219 access, 

1220 lock_deletion=False, 

1221 lock_visibility=True, 

1222 lock_reason=lock_reason 

1223 ) 

1224 

1225 resource_locks.API.create.assert_called_once_with( 

1226 context, resource_id=access['id'], resource_type='access_rule', 

1227 resource_action=constants.RESOURCE_ACTION_SHOW, resource=access, 

1228 lock_reason=lock_reason) 

1229 

1230 def test__create_access_deletion_locks_creation_failed(self): 

1231 access = { 

1232 'id': 'fake', 

1233 'access_type': 'ip', 

1234 'access_to': '127.0.0.1', 

1235 } 

1236 lock_reason = 'locked for testing' 

1237 self.mock_object( 

1238 resource_locks.API, 'create', 

1239 mock.Mock(side_effect=exception.NotAuthorized) 

1240 ) 

1241 

1242 id = 'fake_share_id' 

1243 req = fakes.HTTPRequest.blank( 

1244 '/tenant1/shares/%s/action' % id, version='2.82') 

1245 context = req.environ['manila.context'] 

1246 access['project_id'] = context.project_id 

1247 access['user_id'] = context.user_id 

1248 

1249 self.assertRaises( 

1250 webob.exc.HTTPBadRequest, 

1251 self.controller._create_access_locks, 

1252 req.environ['manila.context'], 

1253 access, 

1254 lock_deletion=True, 

1255 lock_visibility=False, 

1256 lock_reason=lock_reason 

1257 ) 

1258 

1259 resource_locks.API.create.assert_called_once_with( 

1260 context, resource_id=access['id'], resource_type='access_rule', 

1261 resource_action=constants.RESOURCE_ACTION_DELETE, resource=access, 

1262 lock_reason=lock_reason) 

1263 

1264 @ddt.data( 

1265 {'lock_visibility': True, 'lock_deletion': True, 

1266 'lock_reason': 'test lock reason'}, 

1267 {'lock_visibility': True, 'lock_deletion': False, 'lock_reason': None}, 

1268 {'lock_visibility': False, 'lock_deletion': True, 'lock_reason': None}, 

1269 ) 

1270 @ddt.unpack 

1271 def test_allow_access_visibility_restrictions(self, lock_visibility, 

1272 lock_deletion, lock_reason): 

1273 access = {'id': 'fake', 'share_id': 'fake_share_id'} 

1274 expected_access = {'access': {'fake_key': 'fake_value'}} 

1275 self.mock_object(share_api.API, 

1276 'allow_access', 

1277 mock.Mock(return_value=access)) 

1278 self.mock_object(self.controller._access_view_builder, 'view', 

1279 mock.Mock(return_value=expected_access)) 

1280 self.mock_object(self.controller, '_create_access_locks') 

1281 

1282 id = 'fake_share_id' 

1283 body = { 

1284 'allow_access': { 

1285 'access_type': 'ip', 

1286 'access_to': '127.0.0.1', 

1287 'lock_visibility': lock_visibility, 

1288 'lock_deletion': lock_deletion, 

1289 'lock_reason': lock_reason 

1290 } 

1291 } 

1292 req = fakes.HTTPRequest.blank( 

1293 '/tenant1/shares/%s/action' % id, version='2.82') 

1294 context = req.environ['manila.context'] 

1295 access['project_id'] = context.project_id 

1296 access['user_id'] = context.user_id 

1297 

1298 res = self.controller._allow_access( 

1299 req, id, body, lock_visibility=lock_visibility, 

1300 lock_deletion=lock_deletion, lock_reason=lock_reason) 

1301 

1302 self.assertEqual(expected_access, res) 

1303 self.mock_policy_check.assert_called_once_with( 

1304 context, 'share', 'allow_access') 

1305 self.controller._create_access_locks.assert_called_once_with( 

1306 context, access, lock_deletion=lock_deletion, 

1307 lock_visibility=lock_visibility, lock_reason=lock_reason 

1308 ) 

1309 

1310 def test_allow_access_with_network_id(self): 

1311 share_network = db_utils.create_share_network() 

1312 share = db_utils.create_share(share_network_id=share_network['id']) 

1313 access = {'access_type': 'user', 'access_to': '1' * 4} 

1314 

1315 self.mock_object(share_api.API, 

1316 'allow_access', 

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

1318 self.mock_object(self.controller._access_view_builder, 'view', 

1319 mock.Mock(return_value={'access': {'fake': 'fake'}})) 

1320 self.mock_object(share_api.API, 'get', mock.Mock(return_value=share)) 

1321 

1322 id = 'fake_share_id' 

1323 body = {'os-allow_access': access} 

1324 expected = {'access': {'fake': 'fake'}} 

1325 req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) 

1326 

1327 res = self.controller._allow_access(req, id, body) 

1328 

1329 self.assertEqual(expected, res) 

1330 self.mock_policy_check.assert_called_once_with( 

1331 req.environ['manila.context'], 'share', 'allow_access') 

1332 

1333 @ddt.data( 

1334 {'access_type': 'error_type', 'access_to': '127.0.0.1'}, 

1335 {'access_type': 'ip', 'access_to': 'localhost'}, 

1336 {'access_type': 'ip', 'access_to': '127.0.0.*'}, 

1337 {'access_type': 'ip', 'access_to': '127.0.0.0/33'}, 

1338 {'access_type': 'ip', 'access_to': '127.0.0.256'}, 

1339 {'access_type': 'user', 'access_to': '1'}, 

1340 {'access_type': 'user', 'access_to': '1' * 3}, 

1341 {'access_type': 'user', 'access_to': '1' * 256}, 

1342 {'access_type': 'user', 'access_to': 'root<>'}, 

1343 {'access_type': 'user', 'access_to': 'group\\'}, 

1344 {'access_type': 'user', 'access_to': '+=*?group'}, 

1345 {'access_type': 'cert', 'access_to': ''}, 

1346 {'access_type': 'cert', 'access_to': ' '}, 

1347 {'access_type': 'cert', 'access_to': 'x' * 65}, 

1348 {'access_type': 'cephx', 'access_to': 'alice'}, 

1349 {'access_type': 'ip', 'access_to': '127.0.0.0/24', 

1350 'lock_reason': 'fake_lock_reason'}, 

1351 ) 

1352 def test_allow_access_error(self, access): 

1353 id = 'fake_share_id' 

1354 lock_reason = access.pop('lock_reason', None) 

1355 body = {'os-allow_access': access} 

1356 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) 

1357 

1358 self.assertRaises(webob.exc.HTTPBadRequest, 

1359 self.controller._allow_access, req, id, body, 

1360 lock_reason=lock_reason) 

1361 self.mock_policy_check.assert_called_once_with( 

1362 req.environ['manila.context'], 'share', 'allow_access') 

1363 

1364 def test_deny_access(self): 

1365 def _stub_deny_access(*args, **kwargs): 

1366 pass 

1367 

1368 self.mock_object(share_api.API, "deny_access", _stub_deny_access) 

1369 self.mock_object(share_api.API, "access_get", _fake_access_get) 

1370 self.mock_object(self.controller, '_check_for_access_rule_locks') 

1371 

1372 id = 'fake_share_id' 

1373 body = {"os-deny_access": {"access_id": 'fake_acces_id'}} 

1374 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) 

1375 

1376 res = self.controller._deny_access(req, id, body) 

1377 

1378 self.assertEqual(202, res.status_int) 

1379 self.mock_policy_check.assert_called_once_with( 

1380 req.environ['manila.context'], 'share', 'deny_access') 

1381 

1382 def test_deny_access_with_share_network_id(self): 

1383 self.mock_object(share_api.API, "deny_access", mock.Mock()) 

1384 self.mock_object(share_api.API, "access_get", _fake_access_get) 

1385 share_network = db_utils.create_share_network() 

1386 share = db_utils.create_share(share_network_id=share_network['id']) 

1387 self.mock_object(share_api.API, 'get', mock.Mock(return_value=share)) 

1388 self.mock_object(self.controller, '_check_for_access_rule_locks') 

1389 

1390 id = 'fake_share_id' 

1391 access_data = {"access_id": 'fake_acces_id'} 

1392 body = {"os-deny_access": access_data} 

1393 req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) 

1394 

1395 res = self.controller._deny_access(req, id, body) 

1396 

1397 self.assertEqual(202, res.status_int) 

1398 self.controller._check_for_access_rule_locks.assert_called_once_with( 

1399 req.environ['manila.context'], access_data, 

1400 access_data['access_id'], id 

1401 ) 

1402 self.mock_policy_check.assert_called_once_with( 

1403 req.environ['manila.context'], 'share', 'deny_access') 

1404 

1405 def test_deny_access_not_found(self): 

1406 def _stub_deny_access(*args, **kwargs): 

1407 pass 

1408 

1409 self.mock_object(share_api.API, "deny_access", _stub_deny_access) 

1410 self.mock_object(share_api.API, "access_get", _fake_access_get) 

1411 self.mock_object(self.controller, '_check_for_access_rule_locks') 

1412 

1413 id = 'super_fake_share_id' 

1414 body = {"os-deny_access": {"access_id": 'fake_acces_id'}} 

1415 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) 

1416 

1417 self.assertRaises(webob.exc.HTTPNotFound, 

1418 self.controller._deny_access, 

1419 req, 

1420 id, 

1421 body) 

1422 self.mock_policy_check.assert_called_once_with( 

1423 req.environ['manila.context'], 'share', 'deny_access') 

1424 

1425 def test_deny_access_delete_locks(self): 

1426 def _stub_deny_access(*args, **kwargs): 

1427 pass 

1428 

1429 self.mock_object(share_api.API, "deny_access", _stub_deny_access) 

1430 self.mock_object(share_api.API, "access_get", _fake_access_get) 

1431 self.mock_object(self.controller, '_check_for_access_rule_locks') 

1432 

1433 id = 'fake_share_id' 

1434 body_data = {"access_id": 'fake_acces_id'} 

1435 body = {"deny_access": body_data} 

1436 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id, 

1437 version='2.82') 

1438 context = req.environ['manila.context'] 

1439 

1440 res = self.controller._deny_access(req, id, body) 

1441 

1442 self.assertEqual(202, res.status_int) 

1443 self.mock_policy_check.assert_called_once_with( 

1444 req.environ['manila.context'], 'share', 'deny_access') 

1445 self.controller._check_for_access_rule_locks.assert_called_once_with( 

1446 context, body['deny_access'], body_data['access_id'], id 

1447 ) 

1448 

1449 def test__check_for_access_rule_locks_no_locks(self): 

1450 self.mock_object( 

1451 resource_locks.API, "get_all", mock.Mock(return_value=([], 0))) 

1452 

1453 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id, 

1454 version='2.82') 

1455 context = req.environ['manila.context'] 

1456 access_id = 'fake_access_id' 

1457 share_id = 'fake_share_id' 

1458 

1459 self.mock_object(context, 'elevated', mock.Mock(return_value=context)) 

1460 self.controller._check_for_access_rule_locks( 

1461 context, {}, access_id, share_id) 

1462 

1463 delete_search_opts = { 

1464 'resource_id': access_id, 

1465 'resource_action': constants.RESOURCE_ACTION_DELETE, 

1466 'all_projects': True, 

1467 } 

1468 

1469 resource_locks.API.get_all.assert_called_once_with( 

1470 context, search_opts=delete_search_opts, show_count=True 

1471 ) 

1472 

1473 def test__check_for_access_rules_locks_too_many_locks(self): 

1474 locks = [{'id': f'lock_id_{i}'} for i in range(4)] 

1475 self.mock_object( 

1476 resource_locks.API, "get_all", 

1477 mock.Mock(return_value=(locks, len(locks)))) 

1478 

1479 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id, 

1480 version='2.82') 

1481 context = req.environ['manila.context'] 

1482 access_id = 'fake_access_id' 

1483 share_id = 'fake_share_id' 

1484 

1485 self.mock_object(context, 'elevated', mock.Mock(return_value=context)) 

1486 self.assertRaises( 

1487 webob.exc.HTTPForbidden, 

1488 self.controller._check_for_access_rule_locks, 

1489 context, {}, access_id, share_id) 

1490 

1491 delete_search_opts = { 

1492 'resource_id': access_id, 

1493 'resource_action': constants.RESOURCE_ACTION_DELETE, 

1494 'all_projects': True, 

1495 } 

1496 

1497 resource_locks.API.get_all.assert_called_once_with( 

1498 context, search_opts=delete_search_opts, show_count=True 

1499 ) 

1500 

1501 def test__check_for_access_rules_cant_manipulate_lock(self): 

1502 locks = [{ 

1503 'id': 'fake_lock_id', 

1504 'resource_action': constants.RESOURCE_ACTION_DELETE 

1505 }] 

1506 self.mock_object( 

1507 resource_locks.API, "get_all", 

1508 mock.Mock(return_value=(locks, len(locks)))) 

1509 self.mock_object( 

1510 resource_locks.API, "ensure_context_can_delete_lock", 

1511 mock.Mock(side_effect=exception.NotAuthorized)) 

1512 

1513 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id, 

1514 version='2.82') 

1515 context = req.environ['manila.context'] 

1516 access_id = 'fake_access_id' 

1517 share_id = 'fake_share_id' 

1518 

1519 self.mock_object(context, 'elevated', mock.Mock(return_value=context)) 

1520 self.assertRaises( 

1521 webob.exc.HTTPForbidden, 

1522 self.controller._check_for_access_rule_locks, 

1523 context, {'unrestrict': True}, access_id, share_id) 

1524 

1525 delete_search_opts = { 

1526 'resource_id': access_id, 

1527 'resource_action': constants.RESOURCE_ACTION_DELETE, 

1528 'all_projects': True, 

1529 } 

1530 

1531 resource_locks.API.get_all.assert_called_once_with( 

1532 context, search_opts=delete_search_opts, show_count=True 

1533 ) 

1534 (resource_locks.API.ensure_context_can_delete_lock 

1535 .assert_called_once_with( 

1536 context, locks[0]['id'])) 

1537 

1538 def test__check_for_access_rules_locks_unauthorized(self): 

1539 locks = [{ 

1540 'id': 'fake_lock_id', 

1541 'resource_action': constants.RESOURCE_ACTION_DELETE 

1542 }] 

1543 self.mock_object( 

1544 resource_locks.API, "get_all", 

1545 mock.Mock(return_value=(locks, len(locks)))) 

1546 self.mock_object( 

1547 resource_locks.API, "ensure_context_can_delete_lock", 

1548 mock.Mock(side_effect=exception.NotAuthorized)) 

1549 self.mock_object( 

1550 resource_locks.API, "delete", 

1551 mock.Mock(side_effect=exception.NotAuthorized)) 

1552 

1553 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id, 

1554 version='2.82') 

1555 context = req.environ['manila.context'] 

1556 access_id = 'fake_access_id' 

1557 share_id = 'fake_share_id' 

1558 

1559 self.mock_object(context, 'elevated', mock.Mock(return_value=context)) 

1560 self.assertRaises( 

1561 webob.exc.HTTPForbidden, 

1562 self.controller._check_for_access_rule_locks, 

1563 context, {'unrestrict': True}, access_id, share_id 

1564 ) 

1565 delete_search_opts = { 

1566 'resource_id': access_id, 

1567 'resource_action': constants.RESOURCE_ACTION_DELETE, 

1568 'all_projects': True, 

1569 } 

1570 resource_locks.API.get_all.assert_called_once_with( 

1571 context, search_opts=delete_search_opts, show_count=True 

1572 ) 

1573 (resource_locks.API.ensure_context_can_delete_lock 

1574 .assert_called_once_with( 

1575 context, locks[0]['id'])) 

1576 

1577 def test_check_for_access_rules_locks(self): 

1578 locks = [{ 

1579 'id': 'fake_lock_id', 

1580 'resource_action': constants.RESOURCE_ACTION_DELETE 

1581 }] 

1582 self.mock_object( 

1583 resource_locks.API, "get_all", 

1584 mock.Mock(return_value=(locks, len(locks)))) 

1585 self.mock_object( 

1586 resource_locks.API, "ensure_context_can_delete_lock") 

1587 self.mock_object(resource_locks.API, "delete") 

1588 

1589 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id, 

1590 version='2.82') 

1591 context = req.environ['manila.context'] 

1592 access_id = 'fake_access_id' 

1593 share_id = 'fake_share_id' 

1594 

1595 self.mock_object(context, 'elevated', mock.Mock(return_value=context)) 

1596 self.controller._check_for_access_rule_locks( 

1597 context, {'unrestrict': True}, access_id, share_id) 

1598 

1599 delete_search_opts = { 

1600 'resource_id': access_id, 

1601 'resource_action': constants.RESOURCE_ACTION_DELETE, 

1602 'all_projects': True, 

1603 } 

1604 resource_locks.API.get_all.assert_called_once_with( 

1605 context.elevated(), search_opts=delete_search_opts, 

1606 show_count=True 

1607 ) 

1608 (resource_locks.API.ensure_context_can_delete_lock 

1609 .assert_called_once_with( 

1610 context, locks[0]['id'])) 

1611 

1612 @ddt.data('_allow_access', '_deny_access') 

1613 def test_allow_access_deny_access_policy_not_authorized(self, method): 

1614 req = fakes.HTTPRequest.blank('/tenant1/shares/someuuid/action') 

1615 action = method[1:] 

1616 body = {action: None} 

1617 noauthexc = exception.PolicyNotAuthorized(action=action) 

1618 with mock.patch.object( 

1619 policy, 'check_policy', mock.Mock(side_effect=noauthexc)): 

1620 method = getattr(self.controller, method) 

1621 

1622 self.assertRaises( 

1623 webob.exc.HTTPForbidden, method, req, body, 'someuuid') 

1624 policy.check_policy.assert_called_once_with( 

1625 req.environ['manila.context'], 'share', action) 

1626 

1627 def test_access_list(self): 

1628 fake_access_list = [ 

1629 { 

1630 "state": "fakestatus", 

1631 "id": "fake_access_id", 

1632 "access_type": "fakeip", 

1633 "access_to": "127.0.0.1", 

1634 } 

1635 ] 

1636 self.mock_object(self.controller._access_view_builder, 'list_view', 

1637 mock.Mock(return_value={'access_list': 

1638 fake_access_list})) 

1639 id = 'fake_share_id' 

1640 body = {"os-access_list": None} 

1641 req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) 

1642 

1643 res_dict = self.controller._access_list(req, id, body) 

1644 self.assertEqual({'access_list': fake_access_list}, res_dict) 

1645 

1646 def test_extend(self): 

1647 id = 'fake_share_id' 

1648 share = stubs.stub_share_get(None, None, id) 

1649 self.mock_object(share_api.API, 'get', mock.Mock(return_value=share)) 

1650 self.mock_object(share_api.API, "extend") 

1651 

1652 size = '123' 

1653 body = {"os-extend": {'new_size': size}} 

1654 req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) 

1655 

1656 actual_response = self.controller._extend(req, id, body) 

1657 

1658 share_api.API.get.assert_called_once_with(mock.ANY, id) 

1659 share_api.API.extend.assert_called_once_with( 

1660 mock.ANY, share, int(size), force=False) 

1661 self.assertEqual(202, actual_response.status_int) 

1662 

1663 @ddt.data({"os-extend": ""}, 

1664 {"os-extend": {"new_size": "foo"}}, 

1665 {"os-extend": {"new_size": {'foo': 'bar'}}}) 

1666 def test_extend_invalid_body(self, body): 

1667 id = 'fake_share_id' 

1668 req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) 

1669 

1670 self.assertRaises(webob.exc.HTTPBadRequest, 

1671 self.controller._extend, req, id, body) 

1672 

1673 @ddt.data({'source': exception.InvalidInput, 

1674 'target': webob.exc.HTTPBadRequest}, 

1675 {'source': exception.InvalidShare, 

1676 'target': webob.exc.HTTPBadRequest}, 

1677 {'source': exception.ShareSizeExceedsAvailableQuota, 

1678 'target': webob.exc.HTTPForbidden}) 

1679 @ddt.unpack 

1680 def test_extend_exception(self, source, target): 

1681 id = 'fake_share_id' 

1682 req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) 

1683 body = {"os-extend": {'new_size': '123'}} 

1684 self.mock_object(share_api.API, "extend", 

1685 mock.Mock(side_effect=source('fake'))) 

1686 

1687 self.assertRaises(target, self.controller._extend, req, id, body) 

1688 

1689 def test_shrink(self): 

1690 id = 'fake_share_id' 

1691 share = stubs.stub_share_get(None, None, id) 

1692 self.mock_object(share_api.API, 'get', mock.Mock(return_value=share)) 

1693 self.mock_object(share_api.API, "shrink") 

1694 

1695 size = '123' 

1696 body = {"os-shrink": {'new_size': size}} 

1697 req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) 

1698 

1699 actual_response = self.controller._shrink(req, id, body) 

1700 

1701 share_api.API.get.assert_called_once_with(mock.ANY, id) 

1702 share_api.API.shrink.assert_called_once_with( 

1703 mock.ANY, share, int(size)) 

1704 self.assertEqual(202, actual_response.status_int) 

1705 

1706 @ddt.data({"os-shrink": ""}, 

1707 {"os-shrink": {"new_size": "foo"}}, 

1708 {"os-shrink": {"new_size": {'foo': 'bar'}}}) 

1709 def test_shrink_invalid_body(self, body): 

1710 id = 'fake_share_id' 

1711 req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) 

1712 

1713 self.assertRaises(webob.exc.HTTPBadRequest, 

1714 self.controller._shrink, req, id, body) 

1715 

1716 @ddt.data({'source': exception.InvalidInput, 

1717 'target': webob.exc.HTTPBadRequest}, 

1718 {'source': exception.InvalidShare, 

1719 'target': webob.exc.HTTPBadRequest}) 

1720 @ddt.unpack 

1721 def test_shrink_exception(self, source, target): 

1722 id = 'fake_share_id' 

1723 req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) 

1724 body = {"os-shrink": {'new_size': '123'}} 

1725 self.mock_object(share_api.API, "shrink", 

1726 mock.Mock(side_effect=source('fake'))) 

1727 

1728 self.assertRaises(target, self.controller._shrink, req, id, body) 

1729 

1730 

1731@ddt.ddt 

1732class ShareAdminActionsAPITest(test.TestCase): 

1733 

1734 def setUp(self): 

1735 super(ShareAdminActionsAPITest, self).setUp() 

1736 CONF.set_default("default_share_type", None) 

1737 self.flags(transport_url='rabbit://fake:fake@mqhost:5672') 

1738 self.share_api = share_api.API() 

1739 self.admin_context = context.RequestContext('admin', 'fake', True) 

1740 self.member_context = context.RequestContext('fake', 'fake') 

1741 

1742 def _get_context(self, role): 

1743 return getattr(self, '%s_context' % role) 

1744 

1745 def _setup_share_data(self, share=None): 

1746 if share is None: 

1747 share = db_utils.create_share(status=constants.STATUS_AVAILABLE, 

1748 size='1', 

1749 override_defaults=True) 

1750 req = webob.Request.blank('/v2/fake/shares/%s/action' % share['id']) 

1751 return share, req 

1752 

1753 def _reset_status(self, ctxt, model, req, db_access_method, 

1754 valid_code, valid_status=None, body=None): 

1755 if body is None: 

1756 body = {'os-reset_status': {'status': constants.STATUS_ERROR}} 

1757 req.method = 'POST' 

1758 req.headers['content-type'] = 'application/json' 

1759 req.body = jsonutils.dumps(body).encode("utf-8") 

1760 req.environ['manila.context'] = ctxt 

1761 

1762 resp = req.get_response(fakes.app()) 

1763 

1764 # validate response code and model status 

1765 self.assertEqual(valid_code, resp.status_int) 

1766 

1767 if valid_code == 404: 

1768 self.assertRaises(exception.NotFound, 

1769 db_access_method, 

1770 ctxt, 

1771 model['id']) 

1772 else: 

1773 actual_model = db_access_method(ctxt, model['id']) 

1774 self.assertEqual(valid_status, actual_model['status']) 

1775 

1776 @ddt.data( 

1777 { 

1778 'role': 'admin', 

1779 'valid_code': 202, 

1780 'valid_status': constants.STATUS_ERROR, 

1781 }, 

1782 { 

1783 'role': 'member', 

1784 'valid_code': 403, 

1785 'valid_status': constants.STATUS_AVAILABLE, 

1786 }, 

1787 ) 

1788 @ddt.unpack 

1789 def test_share_reset_status_with_different_roles(self, role, valid_code, 

1790 valid_status): 

1791 share, req = self._setup_share_data() 

1792 ctxt = self._get_context(role) 

1793 

1794 self._reset_status(ctxt, share, req, db.share_get, valid_code, 

1795 valid_status) 

1796 

1797 @ddt.data(*fakes.fixture_invalid_reset_status_body) 

1798 def test_share_invalid_reset_status_body(self, body): 

1799 share, req = self._setup_share_data() 

1800 ctxt = self.admin_context 

1801 

1802 self._reset_status(ctxt, share, req, db.share_get, 400, 

1803 constants.STATUS_AVAILABLE, body) 

1804 

1805 def test_share_reset_status_for_missing(self): 

1806 fake_share = {'id': 'missing-share-id'} 

1807 req = webob.Request.blank('/fake/shares/%s/action' % 

1808 fake_share['id']) 

1809 

1810 self._reset_status(self.admin_context, fake_share, req, 

1811 db.share_snapshot_get, 404) 

1812 

1813 def _force_delete(self, ctxt, model, req, db_access_method, valid_code, 

1814 check_model_in_db=False): 

1815 req.method = 'POST' 

1816 req.headers['content-type'] = 'application/json' 

1817 req.body = jsonutils.dumps({'os-force_delete': {}}).encode("utf-8") 

1818 req.environ['manila.context'] = ctxt 

1819 

1820 resp = req.get_response(fakes.app()) 

1821 

1822 # validate response 

1823 self.assertEqual(valid_code, resp.status_int) 

1824 

1825 if valid_code == 202 and check_model_in_db: 

1826 self.assertRaises(exception.NotFound, 

1827 db_access_method, 

1828 ctxt, 

1829 model['id']) 

1830 

1831 @ddt.data( 

1832 {'role': 'admin', 'resp_code': 202}, 

1833 {'role': 'member', 'resp_code': 403}, 

1834 ) 

1835 @ddt.unpack 

1836 def test_share_force_delete_with_different_roles(self, role, resp_code): 

1837 share, req = self._setup_share_data() 

1838 ctxt = self._get_context(role) 

1839 

1840 self._force_delete(ctxt, share, req, db.share_get, resp_code, 

1841 check_model_in_db=True) 

1842 

1843 def test_share_force_delete_missing(self): 

1844 share, req = self._setup_share_data(share={'id': 'fake'}) 

1845 ctxt = self._get_context('admin') 

1846 

1847 self._force_delete(ctxt, share, req, db.share_get, 404)