Skip to content

Commit c45b1d7

Browse files
sunyajingHuanxuan Ao
andcommitted
Fix error for find_service() in identity
if there are more than one services be found with one name, a NoUniqueMatch exception should be raised but we can see a NotFound Exception raised instead. It is because in "find_service()", we use "find_resource()" first, if "find_resource()" return a exception, we just think it is a NotFound Exception and continue to find by type but ignore a NoUniqueMatch exception of "find_resource()". This patch refactor the "find_service()" method to solve this problem. Change-Id: Id4619092c57f276ae0698c89df0d5503b7423a4e Co-Authored-By: Huanxuan Ao <huanxuan.ao@easystack.cn> Closes-Bug:#1597296
1 parent 60639d7 commit c45b1d7

5 files changed

Lines changed: 96 additions & 34 deletions

File tree

openstackclient/identity/common.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,32 @@ def find_service(identity_client, name_type_or_id):
3030
"""Find a service by id, name or type."""
3131

3232
try:
33-
# search for the usual ID or name
34-
return utils.find_resource(identity_client.services, name_type_or_id)
35-
except exceptions.CommandError:
36-
try:
37-
# search for service type
38-
return identity_client.services.find(type=name_type_or_id)
39-
# FIXME(dtroyer): This exception should eventually come from
40-
# common client exceptions
41-
except identity_exc.NotFound:
42-
msg = _("No service with a type, name or ID of '%s' exists.")
43-
raise exceptions.CommandError(msg % name_type_or_id)
44-
except identity_exc.NoUniqueMatch:
45-
msg = _("Multiple service matches found for '%s', "
46-
"use an ID to be more specific.")
47-
raise exceptions.CommandError(msg % name_type_or_id)
33+
# search for service id
34+
return identity_client.services.get(name_type_or_id)
35+
except identity_exc.NotFound:
36+
# ignore NotFound exception, raise others
37+
pass
38+
39+
try:
40+
# search for service name
41+
return identity_client.services.find(name=name_type_or_id)
42+
except identity_exc.NotFound:
43+
pass
44+
except identity_exc.NoUniqueMatch:
45+
msg = _("Multiple service matches found for '%s', "
46+
"use an ID to be more specific.")
47+
raise exceptions.CommandError(msg % name_type_or_id)
48+
49+
try:
50+
# search for service type
51+
return identity_client.services.find(type=name_type_or_id)
52+
except identity_exc.NotFound:
53+
msg = _("No service with a type, name or ID of '%s' exists.")
54+
raise exceptions.CommandError(msg % name_type_or_id)
55+
except identity_exc.NoUniqueMatch:
56+
msg = _("Multiple service matches found for '%s', "
57+
"use an ID to be more specific.")
58+
raise exceptions.CommandError(msg % name_type_or_id)
4859

4960

5061
def _get_token_resource(client, resource, parsed_name):

openstackclient/tests/identity/v2_0/test_endpoint.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,6 @@ def setUp(self):
103103
super(TestEndpointDelete, self).setUp()
104104

105105
self.endpoints_mock.get.return_value = self.fake_endpoint
106-
107-
self.services_mock.get.return_value = self.fake_service
108-
109106
self.endpoints_mock.delete.return_value = None
110107

111108
# Get the command object to test

openstackclient/tests/identity/v2_0/test_service.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
# under the License.
1414
#
1515

16+
from keystoneclient import exceptions as identity_exc
17+
from osc_lib import exceptions
18+
1619
from openstackclient.identity.v2_0 import service
1720
from openstackclient.tests.identity.v2_0 import fakes as identity_fakes
1821

@@ -170,7 +173,8 @@ class TestServiceDelete(TestService):
170173
def setUp(self):
171174
super(TestServiceDelete, self).setUp()
172175

173-
self.services_mock.get.return_value = self.fake_service
176+
self.services_mock.get.side_effect = identity_exc.NotFound(None)
177+
self.services_mock.find.return_value = self.fake_service
174178
self.services_mock.delete.return_value = None
175179

176180
# Get the command object to test
@@ -253,20 +257,23 @@ def test_service_list_long(self):
253257

254258
class TestServiceShow(TestService):
255259

260+
fake_service_s = identity_fakes.FakeService.create_one_service()
261+
256262
def setUp(self):
257263
super(TestServiceShow, self).setUp()
258264

259-
self.services_mock.get.return_value = self.fake_service
265+
self.services_mock.get.side_effect = identity_exc.NotFound(None)
266+
self.services_mock.find.return_value = self.fake_service_s
260267

261268
# Get the command object to test
262269
self.cmd = service.ShowService(self.app, None)
263270

264271
def test_service_show(self):
265272
arglist = [
266-
self.fake_service.name,
273+
self.fake_service_s.name,
267274
]
268275
verifylist = [
269-
('service', self.fake_service.name),
276+
('service', self.fake_service_s.name),
270277
]
271278
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
272279

@@ -275,17 +282,35 @@ def test_service_show(self):
275282
# data to be shown.
276283
columns, data = self.cmd.take_action(parsed_args)
277284

278-
# ServiceManager.get(id)
279-
self.services_mock.get.assert_called_with(
280-
self.fake_service.name,
285+
# ServiceManager.find(id)
286+
self.services_mock.find.assert_called_with(
287+
name=self.fake_service_s.name,
281288
)
282289

283290
collist = ('description', 'id', 'name', 'type')
284291
self.assertEqual(collist, columns)
285292
datalist = (
286-
self.fake_service.description,
287-
self.fake_service.id,
288-
self.fake_service.name,
289-
self.fake_service.type,
293+
self.fake_service_s.description,
294+
self.fake_service_s.id,
295+
self.fake_service_s.name,
296+
self.fake_service_s.type,
290297
)
291298
self.assertEqual(datalist, data)
299+
300+
def test_service_show_nounique(self):
301+
self.services_mock.find.side_effect = identity_exc.NoUniqueMatch(None)
302+
arglist = [
303+
'nounique_service',
304+
]
305+
verifylist = [
306+
('service', 'nounique_service'),
307+
]
308+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
309+
310+
try:
311+
self.cmd.take_action(parsed_args)
312+
self.fail('CommandError should be raised.')
313+
except exceptions.CommandError as e:
314+
self.assertEqual(
315+
"Multiple service matches found for 'nounique_service',"
316+
" use an ID to be more specific.", str(e))

openstackclient/tests/identity/v3/test_service.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
import copy
1717

18+
from keystoneclient import exceptions as identity_exc
19+
from osc_lib import exceptions
20+
1821
from openstackclient.identity.v3 import service
1922
from openstackclient.tests import fakes
2023
from openstackclient.tests.identity.v3 import fakes as identity_fakes
@@ -185,7 +188,8 @@ class TestServiceDelete(TestService):
185188
def setUp(self):
186189
super(TestServiceDelete, self).setUp()
187190

188-
self.services_mock.get.return_value = fakes.FakeResource(
191+
self.services_mock.get.side_effect = identity_exc.NotFound(None)
192+
self.services_mock.find.return_value = fakes.FakeResource(
189193
None,
190194
copy.deepcopy(identity_fakes.SERVICE),
191195
loaded=True,
@@ -282,7 +286,8 @@ class TestServiceSet(TestService):
282286
def setUp(self):
283287
super(TestServiceSet, self).setUp()
284288

285-
self.services_mock.get.return_value = fakes.FakeResource(
289+
self.services_mock.get.side_effect = identity_exc.NotFound(None)
290+
self.services_mock.find.return_value = fakes.FakeResource(
286291
None,
287292
copy.deepcopy(identity_fakes.SERVICE),
288293
loaded=True,
@@ -460,7 +465,8 @@ class TestServiceShow(TestService):
460465
def setUp(self):
461466
super(TestServiceShow, self).setUp()
462467

463-
self.services_mock.get.return_value = fakes.FakeResource(
468+
self.services_mock.get.side_effect = identity_exc.NotFound(None)
469+
self.services_mock.find.return_value = fakes.FakeResource(
464470
None,
465471
copy.deepcopy(identity_fakes.SERVICE),
466472
loaded=True,
@@ -484,8 +490,8 @@ def test_service_show(self):
484490
columns, data = self.cmd.take_action(parsed_args)
485491

486492
# ServiceManager.get(id)
487-
self.services_mock.get.assert_called_with(
488-
identity_fakes.service_name,
493+
self.services_mock.find.assert_called_with(
494+
name=identity_fakes.service_name
489495
)
490496

491497
collist = ('description', 'enabled', 'id', 'name', 'type')
@@ -498,3 +504,21 @@ def test_service_show(self):
498504
identity_fakes.service_type,
499505
)
500506
self.assertEqual(datalist, data)
507+
508+
def test_service_show_nounique(self):
509+
self.services_mock.find.side_effect = identity_exc.NoUniqueMatch(None)
510+
arglist = [
511+
'nounique_service',
512+
]
513+
verifylist = [
514+
('service', 'nounique_service'),
515+
]
516+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
517+
518+
try:
519+
self.cmd.take_action(parsed_args)
520+
self.fail('CommandError should be raised.')
521+
except exceptions.CommandError as e:
522+
self.assertEqual(
523+
"Multiple service matches found for 'nounique_service',"
524+
" use an ID to be more specific.", str(e))
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
fixes:
3+
- Fixed service name lookup in Identity commands to properly handle
4+
multiple matches.
5+
[Bug `1597296 <https://bugs.launchpad.net/python-openstackclient/+bug/1597296>`_]

0 commit comments

Comments
 (0)