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
This commit is contained in:
parent
60639d76a7
commit
c45b1d7b23
@ -30,14 +30,25 @@ def find_service(identity_client, name_type_or_id):
|
|||||||
"""Find a service by id, name or type."""
|
"""Find a service by id, name or type."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# search for the usual ID or name
|
# search for service id
|
||||||
return utils.find_resource(identity_client.services, name_type_or_id)
|
return identity_client.services.get(name_type_or_id)
|
||||||
except exceptions.CommandError:
|
except identity_exc.NotFound:
|
||||||
|
# ignore NotFound exception, raise others
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
# search for service name
|
||||||
|
return identity_client.services.find(name=name_type_or_id)
|
||||||
|
except identity_exc.NotFound:
|
||||||
|
pass
|
||||||
|
except identity_exc.NoUniqueMatch:
|
||||||
|
msg = _("Multiple service matches found for '%s', "
|
||||||
|
"use an ID to be more specific.")
|
||||||
|
raise exceptions.CommandError(msg % name_type_or_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# search for service type
|
# search for service type
|
||||||
return identity_client.services.find(type=name_type_or_id)
|
return identity_client.services.find(type=name_type_or_id)
|
||||||
# FIXME(dtroyer): This exception should eventually come from
|
|
||||||
# common client exceptions
|
|
||||||
except identity_exc.NotFound:
|
except identity_exc.NotFound:
|
||||||
msg = _("No service with a type, name or ID of '%s' exists.")
|
msg = _("No service with a type, name or ID of '%s' exists.")
|
||||||
raise exceptions.CommandError(msg % name_type_or_id)
|
raise exceptions.CommandError(msg % name_type_or_id)
|
||||||
|
@ -103,9 +103,6 @@ class TestEndpointDelete(TestEndpoint):
|
|||||||
super(TestEndpointDelete, self).setUp()
|
super(TestEndpointDelete, self).setUp()
|
||||||
|
|
||||||
self.endpoints_mock.get.return_value = self.fake_endpoint
|
self.endpoints_mock.get.return_value = self.fake_endpoint
|
||||||
|
|
||||||
self.services_mock.get.return_value = self.fake_service
|
|
||||||
|
|
||||||
self.endpoints_mock.delete.return_value = None
|
self.endpoints_mock.delete.return_value = None
|
||||||
|
|
||||||
# Get the command object to test
|
# Get the command object to test
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from keystoneclient import exceptions as identity_exc
|
||||||
|
from osc_lib import exceptions
|
||||||
|
|
||||||
from openstackclient.identity.v2_0 import service
|
from openstackclient.identity.v2_0 import service
|
||||||
from openstackclient.tests.identity.v2_0 import fakes as identity_fakes
|
from openstackclient.tests.identity.v2_0 import fakes as identity_fakes
|
||||||
|
|
||||||
@ -170,7 +173,8 @@ class TestServiceDelete(TestService):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestServiceDelete, self).setUp()
|
super(TestServiceDelete, self).setUp()
|
||||||
|
|
||||||
self.services_mock.get.return_value = self.fake_service
|
self.services_mock.get.side_effect = identity_exc.NotFound(None)
|
||||||
|
self.services_mock.find.return_value = self.fake_service
|
||||||
self.services_mock.delete.return_value = None
|
self.services_mock.delete.return_value = None
|
||||||
|
|
||||||
# Get the command object to test
|
# Get the command object to test
|
||||||
@ -253,20 +257,23 @@ class TestServiceList(TestService):
|
|||||||
|
|
||||||
class TestServiceShow(TestService):
|
class TestServiceShow(TestService):
|
||||||
|
|
||||||
|
fake_service_s = identity_fakes.FakeService.create_one_service()
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestServiceShow, self).setUp()
|
super(TestServiceShow, self).setUp()
|
||||||
|
|
||||||
self.services_mock.get.return_value = self.fake_service
|
self.services_mock.get.side_effect = identity_exc.NotFound(None)
|
||||||
|
self.services_mock.find.return_value = self.fake_service_s
|
||||||
|
|
||||||
# Get the command object to test
|
# Get the command object to test
|
||||||
self.cmd = service.ShowService(self.app, None)
|
self.cmd = service.ShowService(self.app, None)
|
||||||
|
|
||||||
def test_service_show(self):
|
def test_service_show(self):
|
||||||
arglist = [
|
arglist = [
|
||||||
self.fake_service.name,
|
self.fake_service_s.name,
|
||||||
]
|
]
|
||||||
verifylist = [
|
verifylist = [
|
||||||
('service', self.fake_service.name),
|
('service', self.fake_service_s.name),
|
||||||
]
|
]
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
@ -275,17 +282,35 @@ class TestServiceShow(TestService):
|
|||||||
# data to be shown.
|
# data to be shown.
|
||||||
columns, data = self.cmd.take_action(parsed_args)
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
# ServiceManager.get(id)
|
# ServiceManager.find(id)
|
||||||
self.services_mock.get.assert_called_with(
|
self.services_mock.find.assert_called_with(
|
||||||
self.fake_service.name,
|
name=self.fake_service_s.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
collist = ('description', 'id', 'name', 'type')
|
collist = ('description', 'id', 'name', 'type')
|
||||||
self.assertEqual(collist, columns)
|
self.assertEqual(collist, columns)
|
||||||
datalist = (
|
datalist = (
|
||||||
self.fake_service.description,
|
self.fake_service_s.description,
|
||||||
self.fake_service.id,
|
self.fake_service_s.id,
|
||||||
self.fake_service.name,
|
self.fake_service_s.name,
|
||||||
self.fake_service.type,
|
self.fake_service_s.type,
|
||||||
)
|
)
|
||||||
self.assertEqual(datalist, data)
|
self.assertEqual(datalist, data)
|
||||||
|
|
||||||
|
def test_service_show_nounique(self):
|
||||||
|
self.services_mock.find.side_effect = identity_exc.NoUniqueMatch(None)
|
||||||
|
arglist = [
|
||||||
|
'nounique_service',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('service', 'nounique_service'),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
self.fail('CommandError should be raised.')
|
||||||
|
except exceptions.CommandError as e:
|
||||||
|
self.assertEqual(
|
||||||
|
"Multiple service matches found for 'nounique_service',"
|
||||||
|
" use an ID to be more specific.", str(e))
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
from keystoneclient import exceptions as identity_exc
|
||||||
|
from osc_lib import exceptions
|
||||||
|
|
||||||
from openstackclient.identity.v3 import service
|
from openstackclient.identity.v3 import service
|
||||||
from openstackclient.tests import fakes
|
from openstackclient.tests import fakes
|
||||||
from openstackclient.tests.identity.v3 import fakes as identity_fakes
|
from openstackclient.tests.identity.v3 import fakes as identity_fakes
|
||||||
@ -185,7 +188,8 @@ class TestServiceDelete(TestService):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestServiceDelete, self).setUp()
|
super(TestServiceDelete, self).setUp()
|
||||||
|
|
||||||
self.services_mock.get.return_value = fakes.FakeResource(
|
self.services_mock.get.side_effect = identity_exc.NotFound(None)
|
||||||
|
self.services_mock.find.return_value = fakes.FakeResource(
|
||||||
None,
|
None,
|
||||||
copy.deepcopy(identity_fakes.SERVICE),
|
copy.deepcopy(identity_fakes.SERVICE),
|
||||||
loaded=True,
|
loaded=True,
|
||||||
@ -282,7 +286,8 @@ class TestServiceSet(TestService):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestServiceSet, self).setUp()
|
super(TestServiceSet, self).setUp()
|
||||||
|
|
||||||
self.services_mock.get.return_value = fakes.FakeResource(
|
self.services_mock.get.side_effect = identity_exc.NotFound(None)
|
||||||
|
self.services_mock.find.return_value = fakes.FakeResource(
|
||||||
None,
|
None,
|
||||||
copy.deepcopy(identity_fakes.SERVICE),
|
copy.deepcopy(identity_fakes.SERVICE),
|
||||||
loaded=True,
|
loaded=True,
|
||||||
@ -460,7 +465,8 @@ class TestServiceShow(TestService):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestServiceShow, self).setUp()
|
super(TestServiceShow, self).setUp()
|
||||||
|
|
||||||
self.services_mock.get.return_value = fakes.FakeResource(
|
self.services_mock.get.side_effect = identity_exc.NotFound(None)
|
||||||
|
self.services_mock.find.return_value = fakes.FakeResource(
|
||||||
None,
|
None,
|
||||||
copy.deepcopy(identity_fakes.SERVICE),
|
copy.deepcopy(identity_fakes.SERVICE),
|
||||||
loaded=True,
|
loaded=True,
|
||||||
@ -484,8 +490,8 @@ class TestServiceShow(TestService):
|
|||||||
columns, data = self.cmd.take_action(parsed_args)
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
# ServiceManager.get(id)
|
# ServiceManager.get(id)
|
||||||
self.services_mock.get.assert_called_with(
|
self.services_mock.find.assert_called_with(
|
||||||
identity_fakes.service_name,
|
name=identity_fakes.service_name
|
||||||
)
|
)
|
||||||
|
|
||||||
collist = ('description', 'enabled', 'id', 'name', 'type')
|
collist = ('description', 'enabled', 'id', 'name', 'type')
|
||||||
@ -498,3 +504,21 @@ class TestServiceShow(TestService):
|
|||||||
identity_fakes.service_type,
|
identity_fakes.service_type,
|
||||||
)
|
)
|
||||||
self.assertEqual(datalist, data)
|
self.assertEqual(datalist, data)
|
||||||
|
|
||||||
|
def test_service_show_nounique(self):
|
||||||
|
self.services_mock.find.side_effect = identity_exc.NoUniqueMatch(None)
|
||||||
|
arglist = [
|
||||||
|
'nounique_service',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('service', 'nounique_service'),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
self.fail('CommandError should be raised.')
|
||||||
|
except exceptions.CommandError as e:
|
||||||
|
self.assertEqual(
|
||||||
|
"Multiple service matches found for 'nounique_service',"
|
||||||
|
" use an ID to be more specific.", str(e))
|
||||||
|
5
releasenotes/notes/bug-1597296-9735f33eacf5552e.yaml
Normal file
5
releasenotes/notes/bug-1597296-9735f33eacf5552e.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- Fixed service name lookup in Identity commands to properly handle
|
||||||
|
multiple matches.
|
||||||
|
[Bug `1597296 <https://bugs.launchpad.net/python-openstackclient/+bug/1597296>`_]
|
Loading…
Reference in New Issue
Block a user