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
« 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.
18import datetime
19from unittest import mock
20import webob
22import ddt
23from oslo_utils import timeutils
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
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]
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]}
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"
165def fake_service_get_all(context):
166 return fake_services_list
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
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
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']}
192def fake_utcnow():
193 return datetime.datetime(2012, 10, 29, 13, 42, 11)
196@ddt.ddt
197class ServicesTest(test.TestCase):
199 def setUp(self):
200 super(ServicesTest, self).setUp()
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))
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
225 res_dict = controller().index(req)
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')
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
240 res_dict = self.controller.index(req)
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')
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
255 res_dict = self.controller.index(req)
257 response = {'services': [
258 fake_response_service_list['services'][1],
259 fake_response_service_list['services'][3],
260 ]}
262 self.assertEqual(response, res_dict)
263 self.mock_policy_check.assert_called_once_with(
264 req.environ['manila.context'], self.resource_name, 'index')
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
270 res_dict = self.controller.index(req)
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')
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
285 res_dict = self.controller.index(req)
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')
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
298 res_dict = self.controller.index(req)
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')
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
313 res_dict = self.controller.index(req)
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')
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)
330 res_dict = controller().update(req, "enable", body)
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')
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'
351 res_dict = controller().update(req, "disable", body)
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')
358 self.mock_policy_check.assert_called_once_with(
359 req.environ['manila.context'], self.resource_name, 'update')
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'}
374 self.assertRaises(
375 exception.VersionNotFoundForAPIMethod,
376 controller().update,
377 req, "disable", body,
378 )
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)
389 self.assertRaises(
390 exception.VersionNotFoundForAPIMethod, controller().index, req)
392 def test_ensure_shares_no_host_param(self):
393 req = fakes.HTTPRequest.blank(
394 '/fooproject/services/ensure', version=ENSURE_SHARES_VERSION)
395 body = {}
397 self.assertRaises(
398 webob.exc.HTTPBadRequest,
399 self.controller.ensure_shares,
400 req,
401 body
402 )
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'}
410 mock_service_get = self.mock_object(
411 db, 'service_get_by_args',
412 mock.Mock(side_effect=exception.NotFound())
413 )
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 )
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'}
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 )
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 )
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'}
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 )
476 response = self.controller.ensure_shares(req, body)
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 )