diff --git a/openstack/resource.py b/openstack/resource.py index 29358519..177e5c7a 100644 --- a/openstack/resource.py +++ b/openstack/resource.py @@ -933,28 +933,41 @@ class Resource(collections.MutableMapping): :return: The :class:`Resource` object matching the given name or id or None if nothing matches. + :raises: :class:`openstack.exceptions.DuplicateResource` if more + than one resource is found for this request. """ + def get_one_match(data, attr): + if len(info) == 1: + result = cls.existing(**data[0]) + value = getattr(result, attr, False) + if value == name_or_id: + return result + return None + try: args = { cls.id_attribute: name_or_id, 'path_args': path_args, } info = cls.page(session, limit=2, **args) - if len(info) == 1: - return cls.existing(**info[0]) + + result = get_one_match(info, cls.id_attribute) + if result is not None: + return result except exceptions.HttpException: pass if cls.name_attribute: params = {cls.name_attribute: name_or_id} info = cls.page(session, limit=2, path_args=path_args, **params) - if len(info) == 1: - return cls.existing(**info[0]) + if len(info) > 1: msg = "More than one %s exists with the name '%s'." msg = (msg % (cls.get_resource_name(), name_or_id)) raise exceptions.DuplicateResource(msg) + return get_one_match(info, cls.name_attribute) + return None diff --git a/openstack/tests/unit/test_resource.py b/openstack/tests/unit/test_resource.py index 48fb4ec8..70eebba1 100644 --- a/openstack/tests/unit/test_resource.py +++ b/openstack/tests/unit/test_resource.py @@ -1198,7 +1198,7 @@ class TestFind(base.TestCase): self.mock_session = mock.Mock() self.mock_get = mock.Mock() self.mock_session.get = self.mock_get - self.matrix = {'id': self.ID, 'prop': self.PROP} + self.matrix = {'id': self.ID, 'name': self.NAME, 'prop': self.PROP} def test_name(self): self.mock_get.side_effect = [ @@ -1209,7 +1209,7 @@ class TestFind(base.TestCase): result = FakeResource.find(self.mock_session, self.NAME, path_args=fake_arguments) - self.assertEqual(self.ID, result.id) + self.assertEqual(self.NAME, result.name) self.assertEqual(self.PROP, result.prop) p = {'name': self.NAME} @@ -1231,25 +1231,10 @@ class TestFind(base.TestCase): path = fake_path + "?limit=2" self.mock_get.assert_any_call(path, params=p, service=None) - def test_nameo(self): - self.mock_get.side_effect = [ - FakeResponse({FakeResource.resources_key: []}), - FakeResponse({FakeResource.resources_key: [self.matrix]}) - ] - FakeResource.name_attribute = 'nameo' - - result = FakeResource.find(self.mock_session, self.NAME, - path_args=fake_arguments) - FakeResource.name_attribute = 'name' - self.assertEqual(self.ID, result.id) - - p = {'nameo': self.NAME} - path = fake_path + "?limit=2" - self.mock_get.assert_any_call(path, params=p, service=None) - def test_dups(self): dup = {'id': 'Larry'} - resp = FakeResponse({FakeResource.resources_key: [self.matrix, dup]}) + resp = FakeResponse( + {FakeResource.resources_key: [self.matrix, dup]}) self.mock_get.return_value = resp self.assertRaises(exceptions.DuplicateResource, FakeResource.find,