Coverage for manila/tests/api/v2/test_services.py: 94%

164 statements  

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

1# Copyright 2012 IBM Corp. 

2# Copyright 2014 Mirantis Inc. 

3# All Rights Reserved. 

4# 

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

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

7# a copy of the License at 

8# 

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

10# 

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

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

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

14# License for the specific language governing permissions and limitations 

15# under the License. 

16 

17 

18import datetime 

19from unittest import mock 

20import webob 

21 

22import ddt 

23from oslo_utils import timeutils 

24 

25from manila.api.openstack import api_version_request as api_version 

26from manila.api.v2 import services 

27from manila import context 

28from manila import db 

29from manila import exception 

30from manila import policy 

31from manila import test 

32from manila.tests.api import fakes 

33 

34 

35fake_services_list = [ 

36 { 

37 'binary': 'manila-scheduler', 

38 'host': 'host1', 

39 'availability_zone': {'name': 'manila1'}, 

40 'id': 1, 

41 'disabled': True, 

42 'disabled_reason': 'test1', 

43 'state': 'up', 

44 'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 2), 

45 'created_at': datetime.datetime(2012, 9, 18, 2, 46, 27), 

46 }, 

47 { 

48 'binary': 'manila-share', 

49 'host': 'host1', 

50 'availability_zone': {'name': 'manila1'}, 

51 'id': 2, 

52 'disabled': True, 

53 'disabled_reason': 'test2', 

54 'state': 'up', 

55 'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 5), 

56 'created_at': datetime.datetime(2012, 9, 18, 2, 46, 27)}, 

57 { 

58 'binary': 'manila-scheduler', 

59 'host': 'host2', 

60 'availability_zone': {'name': 'manila2'}, 

61 'id': 3, 

62 'disabled': False, 

63 'disabled_reason': '', 

64 'state': 'down', 

65 'updated_at': datetime.datetime(2012, 9, 19, 6, 55, 34), 

66 'created_at': datetime.datetime(2012, 9, 18, 2, 46, 28)}, 

67 { 

68 'binary': 'manila-share', 

69 'host': 'host2', 

70 'availability_zone': {'name': 'manila2'}, 

71 'id': 4, 

72 'disabled': True, 

73 'disabled_reason': 'test4', 

74 'state': 'down', 

75 'updated_at': datetime.datetime(2012, 9, 18, 8, 3, 38), 

76 'created_at': datetime.datetime(2012, 9, 18, 2, 46, 28), 

77 }, 

78] 

79 

80 

81fake_response_service_list = {'services': [ 

82 { 

83 'id': 1, 

84 'binary': 'manila-scheduler', 

85 'host': 'host1', 

86 'zone': 'manila1', 

87 'status': 'disabled', 

88 'state': 'up', 

89 'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 2), 

90 }, 

91 { 

92 'id': 2, 

93 'binary': 'manila-share', 

94 'host': 'host1', 

95 'zone': 'manila1', 

96 'status': 'disabled', 

97 'state': 'up', 

98 'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 5), 

99 }, 

100 { 

101 'id': 3, 

102 'binary': 'manila-scheduler', 

103 'host': 'host2', 

104 'zone': 'manila2', 

105 'status': 'enabled', 

106 'state': 'down', 

107 'updated_at': datetime.datetime(2012, 9, 19, 6, 55, 34), 

108 }, 

109 { 

110 'id': 4, 

111 'binary': 'manila-share', 

112 'host': 'host2', 

113 'zone': 'manila2', 

114 'status': 'disabled', 

115 'state': 'down', 

116 'updated_at': datetime.datetime(2012, 9, 18, 8, 3, 38), 

117 }, 

118]} 

119 

120fake_response_service_list_with_disabled_reason = {'services': [ 

121 { 

122 'id': 1, 

123 'binary': 'manila-scheduler', 

124 'host': 'host1', 

125 'zone': 'manila1', 

126 'status': 'disabled', 

127 'disabled_reason': 'test1', 

128 'state': 'up', 

129 'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 2), 

130 }, 

131 { 

132 'id': 2, 

133 'binary': 'manila-share', 

134 'host': 'host1', 

135 'zone': 'manila1', 

136 'status': 'disabled', 

137 'disabled_reason': 'test2', 

138 'state': 'up', 

139 'updated_at': datetime.datetime(2012, 10, 29, 13, 42, 5), 

140 }, 

141 { 

142 'id': 3, 

143 'binary': 'manila-scheduler', 

144 'host': 'host2', 

145 'zone': 'manila2', 

146 'status': 'enabled', 

147 'disabled_reason': '', 

148 'state': 'down', 

149 'updated_at': datetime.datetime(2012, 9, 19, 6, 55, 34), 

150 }, 

151 { 

152 'id': 4, 

153 'binary': 'manila-share', 

154 'host': 'host2', 

155 'zone': 'manila2', 

156 'status': 'disabled', 

157 'disabled_reason': 'test4', 

158 'state': 'down', 

159 'updated_at': datetime.datetime(2012, 9, 18, 8, 3, 38), 

160 }, 

161]} 

162ENSURE_SHARES_VERSION = "2.86" 

163 

164 

165def fake_service_get_all(context): 

166 return fake_services_list 

167 

168 

169def fake_service_get_by_host_binary(context, host, binary): 

170 for service in fake_services_list: 170 ↛ 173line 170 didn't jump to line 173 because the loop on line 170 didn't complete

171 if service['host'] == host and service['binary'] == binary: 

172 return service 

173 return None 

174 

175 

176def fake_service_get_by_id(value): 

177 for service in fake_services_list: 177 ↛ 180line 177 didn't jump to line 180 because the loop on line 177 didn't complete

178 if service['id'] == value: 

179 return service 

180 return None 

181 

182 

183def fake_service_update(context, service_id, values): 

184 service = fake_service_get_by_id(service_id) 

185 if service is None: 185 ↛ 186line 185 didn't jump to line 186 because the condition on line 185 was never true

186 raise exception.ServiceNotFound(service_id=service_id) 

187 else: 

188 {'host': 'host1', 'binary': 'manila-share', 

189 'disabled': values['disabled']} 

190 

191 

192def fake_utcnow(): 

193 return datetime.datetime(2012, 10, 29, 13, 42, 11) 

194 

195 

196@ddt.ddt 

197class ServicesTest(test.TestCase): 

198 

199 def setUp(self): 

200 super(ServicesTest, self).setUp() 

201 

202 self.mock_object(db, "service_get_all", fake_service_get_all) 

203 self.mock_object(timeutils, "utcnow", fake_utcnow) 

204 self.mock_object(db, "service_get_by_args", 

205 fake_service_get_by_host_binary) 

206 self.mock_object(db, "service_update", fake_service_update) 

207 self.context = context.get_admin_context() 

208 self.controller = services.ServiceController() 

209 self.controller_legacy = services.ServiceControllerLegacy() 

210 self.resource_name = self.controller.resource_name 

211 self.mock_policy_check = self.mock_object( 

212 policy, 'check_policy', mock.Mock(return_value=True)) 

213 

214 @ddt.data( 

215 ('os-services', '1.0', services.ServiceControllerLegacy), 

216 ('os-services', '2.6', services.ServiceControllerLegacy), 

217 ('services', '2.7', services.ServiceController), 

218 ('services', '2.83', services.ServiceController), 

219 ) 

220 @ddt.unpack 

221 def test_services_list(self, url, version, controller): 

222 req = fakes.HTTPRequest.blank('/%s' % url, version=version) 

223 req.environ['manila.context'] = self.context 

224 

225 res_dict = controller().index(req) 

226 

227 if (api_version.APIVersionRequest(version) >= 

228 api_version.APIVersionRequest('2.83')): 

229 self.assertEqual(fake_response_service_list_with_disabled_reason, 

230 res_dict) 

231 else: 

232 self.assertEqual(fake_response_service_list, res_dict) 

233 self.mock_policy_check.assert_called_once_with( 

234 req.environ['manila.context'], self.resource_name, 'index') 

235 

236 def test_services_list_with_host(self): 

237 req = fakes.HTTPRequest.blank('/services?host=host1', version='2.7') 

238 req.environ['manila.context'] = self.context 

239 

240 res_dict = self.controller.index(req) 

241 

242 response = {'services': [ 

243 fake_response_service_list['services'][0], 

244 fake_response_service_list['services'][1], 

245 ]} 

246 self.assertEqual(response, res_dict) 

247 self.mock_policy_check.assert_called_once_with( 

248 req.environ['manila.context'], self.resource_name, 'index') 

249 

250 def test_services_list_with_binary(self): 

251 req = fakes.HTTPRequest.blank( 

252 '/services?binary=manila-share', version='2.7') 

253 req.environ['manila.context'] = self.context 

254 

255 res_dict = self.controller.index(req) 

256 

257 response = {'services': [ 

258 fake_response_service_list['services'][1], 

259 fake_response_service_list['services'][3], 

260 ]} 

261 

262 self.assertEqual(response, res_dict) 

263 self.mock_policy_check.assert_called_once_with( 

264 req.environ['manila.context'], self.resource_name, 'index') 

265 

266 def test_services_list_with_zone(self): 

267 req = fakes.HTTPRequest.blank('/services?zone=manila1', version='2.7') 

268 req.environ['manila.context'] = self.context 

269 

270 res_dict = self.controller.index(req) 

271 

272 response = {'services': [ 

273 fake_response_service_list['services'][0], 

274 fake_response_service_list['services'][1], 

275 ]} 

276 self.assertEqual(response, res_dict) 

277 self.mock_policy_check.assert_called_once_with( 

278 req.environ['manila.context'], self.resource_name, 'index') 

279 

280 def test_services_list_with_status(self): 

281 req = fakes.HTTPRequest.blank( 

282 '/services?status=enabled', version='2.7') 

283 req.environ['manila.context'] = self.context 

284 

285 res_dict = self.controller.index(req) 

286 

287 response = {'services': [ 

288 fake_response_service_list['services'][2], 

289 ]} 

290 self.assertEqual(response, res_dict) 

291 self.mock_policy_check.assert_called_once_with( 

292 req.environ['manila.context'], self.resource_name, 'index') 

293 

294 def test_services_list_with_state(self): 

295 req = fakes.HTTPRequest.blank('/services?state=up', version='2.7') 

296 req.environ['manila.context'] = self.context 

297 

298 res_dict = self.controller.index(req) 

299 

300 response = {'services': [ 

301 fake_response_service_list['services'][0], 

302 fake_response_service_list['services'][1], 

303 ]} 

304 self.assertEqual(response, res_dict) 

305 self.mock_policy_check.assert_called_once_with( 

306 req.environ['manila.context'], self.resource_name, 'index') 

307 

308 def test_services_list_with_host_binary(self): 

309 req = fakes.HTTPRequest.blank( 

310 "/services?binary=manila-share&state=up", version='2.7') 

311 req.environ['manila.context'] = self.context 

312 

313 res_dict = self.controller.index(req) 

314 

315 response = {'services': [fake_response_service_list['services'][1], ]} 

316 self.assertEqual(response, res_dict) 

317 self.mock_policy_check.assert_called_once_with( 

318 req.environ['manila.context'], self.resource_name, 'index') 

319 

320 @ddt.data( 

321 ('os-services', '1.0', services.ServiceControllerLegacy), 

322 ('os-services', '2.6', services.ServiceControllerLegacy), 

323 ('services', '2.7', services.ServiceController), 

324 ) 

325 @ddt.unpack 

326 def test_services_enable(self, url, version, controller): 

327 body = {'host': 'host1', 'binary': 'manila-share'} 

328 req = fakes.HTTPRequest.blank('/fooproject/%s' % url, version=version) 

329 

330 res_dict = controller().update(req, "enable", body) 

331 

332 self.assertEqual('enabled', res_dict['status']) 

333 self.mock_policy_check.assert_called_once_with( 

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

335 

336 @ddt.data( 

337 ('os-services', '1.0', services.ServiceControllerLegacy), 

338 ('os-services', '2.6', services.ServiceControllerLegacy), 

339 ('services', '2.7', services.ServiceController), 

340 ('services', '2.83', services.ServiceController), 

341 ) 

342 @ddt.unpack 

343 def test_services_disable(self, url, version, controller): 

344 req = fakes.HTTPRequest.blank( 

345 '/fooproject/%s/disable' % url, version=version) 

346 body = {'host': 'host1', 'binary': 'manila-share'} 

347 if (api_version.APIVersionRequest(version) > 347 ↛ 349line 347 didn't jump to line 349 because the condition on line 347 was never true

348 api_version.APIVersionRequest("2.83")): 

349 body['disabled_reason'] = 'test1' 

350 

351 res_dict = controller().update(req, "disable", body) 

352 

353 self.assertEqual('disabled', res_dict['status']) 

354 if (api_version.APIVersionRequest(version) > 354 ↛ 356line 354 didn't jump to line 356 because the condition on line 354 was never true

355 api_version.APIVersionRequest("2.83")): 

356 self.assertEqual(res_dict['disabled_reason'], 'test1') 

357 

358 self.mock_policy_check.assert_called_once_with( 

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

360 

361 @ddt.data( 

362 ('os-services', '2.7', services.ServiceControllerLegacy), 

363 ('services', '2.6', services.ServiceController), 

364 ('services', '1.0', services.ServiceController), 

365 ) 

366 @ddt.unpack 

367 def test_services_update_legacy_url_2_dot_7_api_not_found(self, url, 

368 version, 

369 controller): 

370 req = fakes.HTTPRequest.blank( 

371 '/fooproject/%s/fake' % url, version=version) 

372 body = {'host': 'host1', 'binary': 'manila-share'} 

373 

374 self.assertRaises( 

375 exception.VersionNotFoundForAPIMethod, 

376 controller().update, 

377 req, "disable", body, 

378 ) 

379 

380 @ddt.data( 

381 ('os-services', '2.7', services.ServiceControllerLegacy), 

382 ('services', '2.6', services.ServiceController), 

383 ('services', '1.0', services.ServiceController), 

384 ) 

385 @ddt.unpack 

386 def test_services_list_api_not_found(self, url, version, controller): 

387 req = fakes.HTTPRequest.blank('/fooproject/%s' % url, version=version) 

388 

389 self.assertRaises( 

390 exception.VersionNotFoundForAPIMethod, controller().index, req) 

391 

392 def test_ensure_shares_no_host_param(self): 

393 req = fakes.HTTPRequest.blank( 

394 '/fooproject/services/ensure', version=ENSURE_SHARES_VERSION) 

395 body = {} 

396 

397 self.assertRaises( 

398 webob.exc.HTTPBadRequest, 

399 self.controller.ensure_shares, 

400 req, 

401 body 

402 ) 

403 

404 def test_ensure_shares_host_not_found(self): 

405 req = fakes.HTTPRequest.blank( 

406 '/fooproject/services/ensure', version=ENSURE_SHARES_VERSION) 

407 req_context = req.environ['manila.context'] 

408 body = {'host': 'host1'} 

409 

410 mock_service_get = self.mock_object( 

411 db, 'service_get_by_args', 

412 mock.Mock(side_effect=exception.NotFound()) 

413 ) 

414 

415 self.assertRaises( 

416 webob.exc.HTTPNotFound, 

417 self.controller.ensure_shares, 

418 req, 

419 body 

420 ) 

421 mock_service_get.assert_called_once_with( 

422 req_context, 

423 body['host'], 

424 'manila-share' 

425 ) 

426 

427 def test_ensure_shares_conflict(self): 

428 req = fakes.HTTPRequest.blank( 

429 '/fooproject/services/ensure', version=ENSURE_SHARES_VERSION) 

430 req_context = req.environ['manila.context'] 

431 body = {'host': 'host1'} 

432 fake_service = {'id': 'fake_service_id'} 

433 

434 mock_service_get = self.mock_object( 

435 db, 

436 'service_get_by_args', 

437 mock.Mock(return_value=fake_service) 

438 ) 

439 mock_ensure = self.mock_object( 

440 self.controller.service_api, 

441 'ensure_shares', 

442 mock.Mock(side_effect=webob.exc.HTTPConflict) 

443 ) 

444 

445 self.assertRaises( 

446 webob.exc.HTTPConflict, 

447 self.controller.ensure_shares, 

448 req, 

449 body 

450 ) 

451 mock_service_get.assert_called_once_with( 

452 req_context, 

453 body['host'], 

454 'manila-share' 

455 ) 

456 mock_ensure.assert_called_once_with( 

457 req_context, fake_service, body['host'] 

458 ) 

459 

460 def test_ensure_shares(self): 

461 req = fakes.HTTPRequest.blank( 

462 '/fooproject/services/ensure', version=ENSURE_SHARES_VERSION) 

463 req_context = req.environ['manila.context'] 

464 body = {'host': 'host1'} 

465 fake_service = {'id': 'fake_service_id'} 

466 

467 mock_service_get = self.mock_object( 

468 db, 

469 'service_get_by_args', 

470 mock.Mock(return_value=fake_service) 

471 ) 

472 mock_ensure = self.mock_object( 

473 self.controller.service_api, 'ensure_shares', 

474 ) 

475 

476 response = self.controller.ensure_shares(req, body) 

477 

478 self.assertEqual(202, response.status_int) 

479 mock_service_get.assert_called_once_with( 

480 req_context, 

481 body['host'], 

482 'manila-share' 

483 ) 

484 mock_ensure.assert_called_once_with( 

485 req_context, fake_service, body['host'] 

486 )