Add find method to resource

Add a find method to the resource to search by name or id.

Change-Id: I993e0ab2fffd3cd10407406316c483f8051dca1b
This commit is contained in:
Terry Howe 2014-07-03 14:48:34 -06:00
parent 445809d8e9
commit 67e0fae211
3 changed files with 114 additions and 0 deletions

View File

@ -66,3 +66,13 @@ class HttpException(SDKException):
class MethodNotSupported(SDKException): class MethodNotSupported(SDKException):
"""The resource does not support this operation type.""" """The resource does not support this operation type."""
pass pass
class ResourceNotFound(SDKException):
"""The requested resource was not found."""
pass
class DuplicateResource(SDKException):
"""More than one resource exists with that name."""
pass

View File

@ -101,6 +101,9 @@ class Resource(collections.MutableMapping):
resource_key = None resource_key = None
resources_key = None resources_key = None
# The attribute associated with the name
name_attribute = 'name'
# the base part of the url for this resource # the base part of the url for this resource
base_path = '' base_path = ''
@ -350,3 +353,24 @@ class Resource(collections.MutableMapping):
resp = resp[cls.resources_key] resp = resp[cls.resources_key]
return [cls.existing(**data) for data in resp] return [cls.existing(**data) for data in resp]
@classmethod
def find(cls, session, name_or_id):
try:
info = cls.list(session, id=name_or_id, fields='id')
if len(info) == 1:
return info[0]
except exceptions.HttpException:
pass
if cls.name_attribute:
params = {cls.name_attribute: name_or_id, 'fields': 'id'}
info = cls.list(session, **params)
if len(info) == 1:
return info[0]
if len(info) > 1:
msg = "More than one %s exists with the name '%s'."
msg = (msg % (cls.resource_key, name_or_id))
raise exceptions.DuplicateResource(msg)
msg = ("No %s with a name or ID of '%s' exists." %
(cls.resource_key, name_or_id))
raise exceptions.ResourceNotFound(msg)

View File

@ -11,7 +11,9 @@
# under the License. # under the License.
import httpretty import httpretty
import mock
from openstack import exceptions
from openstack import resource from openstack import resource
from openstack import session from openstack import session
from openstack.tests import base from openstack.tests import base
@ -206,3 +208,81 @@ class ResourceTests(base.TestTransportBase):
pass pass
else: else:
self.fail("Didn't raise attribute error") self.fail("Didn't raise attribute error")
class FakeResponse:
def __init__(self, response):
self.body = response
class TestFind(base.TestCase):
NAME = 'matrix'
ID = 'Fishburne'
def setUp(self):
super(TestFind, self).setUp()
self.mock_session = mock.Mock()
self.mock_get = mock.Mock()
self.mock_session.get = self.mock_get
self.matrix = {'id': self.ID}
def test_name(self):
self.mock_get.side_effect = [
FakeResponse({FakeResource.resources_key: []}),
FakeResponse({FakeResource.resources_key: [self.matrix]})
]
result = FakeResource.find(self.mock_session, self.NAME)
self.assertEqual(self.ID, result.id)
p = {'fields': 'id', 'name': self.NAME}
self.mock_get.assert_called_with('/fakes', params=p, service=None)
def test_id(self):
resp = FakeResponse({FakeResource.resources_key: [self.matrix]})
self.mock_get.return_value = resp
result = FakeResource.find(self.mock_session, self.ID)
self.assertEqual(self.ID, result.id)
p = {'fields': 'id', 'id': self.ID}
self.mock_get.assert_called_with('/fakes', 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)
FakeResource.name_attribute = 'name'
self.assertEqual(self.ID, result.id)
p = {'fields': 'id', 'nameo': self.NAME}
self.mock_get.assert_called_with('/fakes', params=p, service=None)
def test_dups(self):
dup = {'id': 'Larry'}
resp = FakeResponse({FakeResource.resources_key: [self.matrix, dup]})
self.mock_get.return_value = resp
self.assertRaises(exceptions.DuplicateResource, FakeResource.find,
self.mock_session, self.NAME)
def test_nada(self):
resp = FakeResponse({FakeResource.resources_key: []})
self.mock_get.return_value = resp
self.assertRaises(exceptions.ResourceNotFound, FakeResource.find,
self.mock_session, self.NAME)
def test_no_name(self):
self.mock_get.side_effect = [
FakeResponse({FakeResource.resources_key: []}),
FakeResponse({FakeResource.resources_key: [self.matrix]})
]
FakeResource.name_attribute = None
self.assertRaises(exceptions.ResourceNotFound, FakeResource.find,
self.mock_session, self.NAME)